@rspress/plugin-llms 2.0.0-beta.3 → 2.0.0-beta.31

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,42 +70,56 @@ 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
+ 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
+ return compiler.process({
209
106
  value: content,
210
107
  path: filepath
211
108
  });
212
109
  }
213
- const rsbuildPluginLlms = ({ pageDataList, routes, titleRef, descriptionRef, langRef, sidebar, baseRef, docDirectoryRef, routeServiceRef, nav, rspressPluginOptions })=>({
214
- name: 'rsbuild-plugin-llms',
110
+ const rsbuildPluginLlms = ({ disableSSGRef, baseRef, pageDataList, routes, titleRef, descriptionRef, langRef, sidebar, routeServiceRef, nav, rspressPluginOptions, index = 0 })=>({
111
+ name: `rsbuild-plugin-llms-${index}`,
215
112
  async setup (api) {
216
- const { llmsTxt = true, mdFiles = true, llmsFullTxt = true, include, exclude } = rspressPluginOptions;
113
+ const { llmsTxt = {
114
+ name: 'llms.txt'
115
+ }, mdFiles = {
116
+ mdxToMd: false,
117
+ remarkPlugins: []
118
+ }, llmsFullTxt = {
119
+ name: 'llms-full.txt'
120
+ }, include, exclude } = rspressPluginOptions;
217
121
  api.onBeforeBuild(async ()=>{
218
- const base = baseRef.current;
219
- const docDirectory = docDirectoryRef.current;
122
+ const disableSSG = disableSSGRef.current;
220
123
  const newPageDataList = mergeRouteMetaWithPageData(routes, pageDataList, langRef.current, include, exclude);
221
124
  const navList = Array.isArray(nav) ? nav.map((i)=>{
222
125
  const nav = i.nav.default;
@@ -233,21 +136,24 @@ const rsbuildPluginLlms = ({ pageDataList, routes, titleRef, descriptionRef, lan
233
136
  for(let i = 0; i < pageArray.length; i++){
234
137
  const pageArrayItem = pageArray[i];
235
138
  const navItem = navList[i];
236
- 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);
139
+ if (lang === navItem.lang && new RegExp(navItem.activeMatch ?? navItem.link).test(routePath)) return void pageArrayItem.push(pageData);
237
140
  }
238
141
  others.push(pageData);
239
142
  });
240
- for (const array of pageArray)organizeBySidebar(sidebar, array, base);
143
+ for (const array of pageArray)organizeBySidebar(sidebar, array);
241
144
  if (llmsTxt) {
242
- const llmsTxtContent = generateLlmsTxt(pageArray, navList, others, rspressPluginOptions.llmsTxt ?? {}, titleRef.current, descriptionRef.current);
145
+ const { name } = llmsTxt;
146
+ const llmsTxtContent = generateLlmsTxt(pageArray, navList, others, llmsTxt, titleRef.current, descriptionRef.current, baseRef.current);
243
147
  api.processAssets({
244
- targets: [
148
+ environments: disableSSG ? [
149
+ 'web'
150
+ ] : [
245
151
  'node'
246
152
  ],
247
153
  stage: 'additional'
248
154
  }, async ({ compilation, sources })=>{
249
155
  const source = new sources.RawSource(llmsTxtContent);
250
- compilation.emitAsset('llms.txt', source);
156
+ compilation.emitAsset(name, source);
251
157
  });
252
158
  }
253
159
  const mdContents = {};
@@ -256,22 +162,21 @@ const rsbuildPluginLlms = ({ pageDataList, routes, titleRef, descriptionRef, lan
256
162
  ].map(async (pageData)=>{
257
163
  const content = pageData._flattenContent ?? pageData.content;
258
164
  const filepath = pageData._filepath;
259
- const isMD = 'mdx' !== __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].extname(filepath).slice(1);
165
+ const isMD = 'mdx' !== node_path.extname(filepath).slice(1);
260
166
  let mdContent;
261
- if (isMD) mdContent = content;
262
- else try {
263
- mdContent = (await mdxToMd(content, filepath, docDirectory, routeServiceRef.current)).toString();
167
+ try {
168
+ mdContent = (await normalizeMdFile(content, filepath, routeServiceRef.current, baseRef.current, 'boolean' != typeof mdFiles ? mdFiles?.mdxToMd ?? false : false, isMD, 'boolean' != typeof mdFiles ? mdFiles?.remarkPlugins ?? [] : [])).toString();
264
169
  } catch (e) {
265
- __WEBPACK_EXTERNAL_MODULE__rspress_shared_logger_4374e44a__.logger.debug(e);
170
+ logger.debug('normalizeMdFile failed', pageData.routePath, e);
266
171
  mdContent = content;
267
- return;
268
172
  }
269
- pageData.mdContent = mdContent;
270
- const outFilePath = `${pageData.routePath.endsWith('/') ? `${pageData.routePath}index` : pageData.routePath}.md`;
173
+ const outFilePath = routePathToMdPath(pageData.routePath, '');
271
174
  mdContents[outFilePath] = mdContent.toString();
272
175
  }) ?? []);
273
176
  if (mdFiles) api.processAssets({
274
- targets: [
177
+ environments: disableSSG ? [
178
+ 'web'
179
+ ] : [
275
180
  'node'
276
181
  ],
277
182
  stage: 'additional'
@@ -282,15 +187,18 @@ const rsbuildPluginLlms = ({ pageDataList, routes, titleRef, descriptionRef, lan
282
187
  });
283
188
  });
284
189
  if (llmsFullTxt) {
285
- const llmsFullTxtContent = generateLlmsFullTxt(pageArray, navList, others);
190
+ const { name } = llmsFullTxt;
191
+ const llmsFullTxtContent = generateLlmsFullTxt(pageArray, navList, others, baseRef.current);
286
192
  api.processAssets({
287
- targets: [
193
+ targets: disableSSG ? [
194
+ 'web'
195
+ ] : [
288
196
  'node'
289
197
  ],
290
198
  stage: 'additional'
291
199
  }, async ({ compilation, sources })=>{
292
200
  const source = new sources.RawSource(llmsFullTxtContent);
293
- compilation.emitAsset('llms-full.txt', source);
201
+ compilation.emitAsset(name, source);
294
202
  });
295
203
  }
296
204
  });
@@ -330,19 +238,45 @@ function flatSidebar(sidebar) {
330
238
  if ('items' in i && Array.isArray(i.items)) return flatSidebar(i.items);
331
239
  }).filter(Boolean);
332
240
  }
333
- function organizeBySidebar(sidebar, pages, base) {
241
+ function organizeBySidebar(sidebar, pages) {
334
242
  if (0 === pages.length) return;
335
243
  const pageItem = pages[0];
336
- const currSidebar = (0, __WEBPACK_EXTERNAL_MODULE__rspress_shared_baa012d0__.getSidebarDataGroup)(sidebar, pageItem.routePath, base);
244
+ const currSidebar = getSidebarDataGroup(sidebar, pageItem.routePath);
337
245
  if (0 === currSidebar.length) return;
338
246
  const orderList = flatSidebar(currSidebar);
339
247
  pages.sort((a, b)=>{
340
- const aIndex = orderList.findIndex((order)=>matchPath(order, a.routePath));
341
- const bIndex = orderList.findIndex((order)=>matchPath(order, b.routePath));
248
+ let aIndex = orderList.findIndex((order)=>matchPath(order, a.routePath));
249
+ if (-1 === aIndex) aIndex = Number.MAX_SAFE_INTEGER;
250
+ let bIndex = orderList.findIndex((order)=>matchPath(order, b.routePath));
251
+ if (-1 === bIndex) bIndex = Number.MAX_SAFE_INTEGER;
342
252
  return aIndex - bIndex;
343
253
  });
344
254
  }
345
- function pluginLlms(options = {}) {
255
+ function getDefaultOptions(lang, langs) {
256
+ if (!lang || 0 === langs.length) return {};
257
+ return langs.map((l)=>{
258
+ if (l === lang) return {
259
+ llmsTxt: {
260
+ name: 'llms.txt'
261
+ },
262
+ llmsFullTxt: {
263
+ name: 'llms-full.txt'
264
+ }
265
+ };
266
+ return {
267
+ llmsTxt: {
268
+ name: `${l}/llms.txt`
269
+ },
270
+ llmsFullTxt: {
271
+ name: `${l}/llms-full.txt`
272
+ },
273
+ include ({ page }) {
274
+ return page.lang === l;
275
+ }
276
+ };
277
+ });
278
+ }
279
+ function pluginLlms(options) {
346
280
  const baseRef = {
347
281
  current: ''
348
282
  };
@@ -361,6 +295,9 @@ function pluginLlms(options = {}) {
361
295
  const pageDataList = [];
362
296
  const routes = [];
363
297
  const sidebar = {};
298
+ const disableSSGRef = {
299
+ current: false
300
+ };
364
301
  const nav = [];
365
302
  const routeServiceRef = {
366
303
  current: void 0
@@ -376,40 +313,71 @@ function pluginLlms(options = {}) {
376
313
  routeGenerated (_routes, isProd) {
377
314
  if (isProd) routes.push(..._routes);
378
315
  },
316
+ config (config) {
317
+ config.themeConfig = config.themeConfig || {};
318
+ config.themeConfig.locales = config.themeConfig.locales || config.locales || [];
319
+ const langs = config.themeConfig.locales.map((locale)=>locale.lang);
320
+ let mergedOptions;
321
+ mergedOptions = void 0 === options ? getDefaultOptions(config.lang, langs) : options;
322
+ if (!config.builderConfig) config.builderConfig = {};
323
+ if (!config.builderConfig.plugins) config.builderConfig.plugins = [];
324
+ config.builderConfig.plugins.push(...Array.isArray(mergedOptions) ? mergedOptions.map((item, index)=>rsbuildPluginLlms({
325
+ pageDataList,
326
+ routes,
327
+ titleRef,
328
+ descriptionRef,
329
+ langRef,
330
+ sidebar,
331
+ routeServiceRef,
332
+ nav,
333
+ baseRef,
334
+ disableSSGRef,
335
+ rspressPluginOptions: item,
336
+ index
337
+ })) : [
338
+ rsbuildPluginLlms({
339
+ pageDataList,
340
+ routes,
341
+ titleRef,
342
+ descriptionRef,
343
+ langRef,
344
+ sidebar,
345
+ routeServiceRef,
346
+ nav,
347
+ baseRef,
348
+ disableSSGRef,
349
+ rspressPluginOptions: mergedOptions
350
+ })
351
+ ]);
352
+ return config;
353
+ },
379
354
  beforeBuild (config) {
380
- const configSidebar = config?.themeConfig?.locales?.map((i)=>i.sidebar).reduce((prev, curr)=>{
355
+ disableSSGRef.current = false === config.ssg;
356
+ const locales = config.themeConfig?.locales;
357
+ const isMultiLang = locales && locales.length > 0;
358
+ const sidebars = isMultiLang ? locales.map((i)=>i.sidebar) : [
359
+ config.themeConfig?.sidebar
360
+ ];
361
+ const configSidebar = sidebars.reduce((prev, curr)=>{
381
362
  Object.assign(prev, curr);
382
363
  return prev;
383
364
  }, {});
384
365
  Object.assign(sidebar, configSidebar);
385
- const configNav = config.themeConfig?.locales?.filter((i)=>Boolean(i.nav))?.map((i)=>({
366
+ const configNav = isMultiLang ? locales.filter((i)=>Boolean(i.nav)).map((i)=>({
386
367
  nav: i.nav,
387
368
  lang: i.lang
388
- }));
369
+ })) : [
370
+ {
371
+ nav: config.themeConfig?.nav,
372
+ lang: config.lang ?? ''
373
+ }
374
+ ];
389
375
  nav.push(...configNav);
390
376
  titleRef.current = config.title;
391
377
  descriptionRef.current = config.description;
392
- langRef.current = config.lang;
378
+ langRef.current = config.lang ?? '';
393
379
  baseRef.current = config.base ?? '/';
394
380
  docDirectoryRef.current = config.root ?? 'docs';
395
- },
396
- builderConfig: {
397
- plugins: [
398
- rsbuildPluginLlms({
399
- ...options,
400
- pageDataList,
401
- routes,
402
- titleRef,
403
- descriptionRef,
404
- langRef,
405
- sidebar,
406
- docDirectoryRef,
407
- routeServiceRef,
408
- nav,
409
- baseRef,
410
- rspressPluginOptions: options
411
- })
412
- ]
413
381
  }
414
382
  };
415
383
  }
@@ -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,357 @@
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: _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: "\u590D\u5236 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
+ _4,
117
+ isLoading ? _5 : '',
118
+ isFinished ? _6 : ''
119
+ ].filter(Boolean).join(' '),
120
+ onClick: onClick ?? handleClick,
121
+ children: [
122
+ /*#__PURE__*/ jsxs("div", {
123
+ className: LlmsCopyButton_module_1,
124
+ children: [
125
+ /*#__PURE__*/ jsx(IconSuccess, {
126
+ className: _3
127
+ }),
128
+ /*#__PURE__*/ jsx(IconCopy, {
129
+ className: _2
130
+ })
131
+ ]
132
+ }),
133
+ /*#__PURE__*/ jsx("span", {
134
+ children: text ?? textByLang?.[lang] ?? 'Copy Markdown'
135
+ })
136
+ ]
137
+ });
138
+ }
139
+ var LlmsViewOptions_module_1 = "active-SacMuO";
140
+ var LlmsViewOptions_module_2 = "dropdownArrow-UjqrjW";
141
+ var LlmsViewOptions_module_3 = "dropdownButton-Mj4g7p";
142
+ var LlmsViewOptions_module_4 = "dropdownItem-taWikf";
143
+ var LlmsViewOptions_module_5 = "dropdownMenu-_ggfjT";
144
+ var LlmsViewOptions_module_6 = "externalIcon-r8tMpa";
145
+ var _8 = "leftIcon-JI6iFK";
146
+ var _9 = "rotated-YGs7Vp";
147
+ /**
148
+ * Inspired from fumadocs docsite
149
+ * @from https://github.com/fuma-nama/fumadocs/blob/5723bbe58ef805a5421a780abf235a10b251be2f/apps/docs/app/docs/%5B...slug%5D/page.client.tsx#L11
150
+ * @license MIT
151
+ */ const IconArrow = ({ className })=>/*#__PURE__*/ jsx("svg", {
152
+ className: className,
153
+ xmlns: "http://www.w3.org/2000/svg",
154
+ width: "16",
155
+ height: "16",
156
+ viewBox: "0 0 15 16",
157
+ fill: "none",
158
+ children: /*#__PURE__*/ jsx("path", {
159
+ d: "M11.125 5.27885L7 9.72115L2.875 5.27885",
160
+ stroke: "#4E5969",
161
+ strokeWidth: "1.125",
162
+ strokeLinecap: "round",
163
+ strokeLinejoin: "round"
164
+ })
165
+ });
166
+ const IconExternalLink = ()=>/*#__PURE__*/ jsxs("svg", {
167
+ xmlns: "http://www.w3.org/2000/svg",
168
+ width: "16",
169
+ height: "16",
170
+ viewBox: "0 0 16 16",
171
+ fill: "none",
172
+ children: [
173
+ /*#__PURE__*/ jsx("path", {
174
+ d: "M9.33301 2H13.9997V6.66667",
175
+ stroke: "#808080",
176
+ strokeWidth: "1.33333",
177
+ strokeLinecap: "round",
178
+ strokeLinejoin: "round"
179
+ }),
180
+ /*#__PURE__*/ jsx("path", {
181
+ 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",
182
+ stroke: "#808080",
183
+ strokeWidth: "1.33333",
184
+ strokeLinecap: "round",
185
+ strokeLinejoin: "round"
186
+ }),
187
+ /*#__PURE__*/ jsx("path", {
188
+ d: "M8.59961 7.39996L13.6996 2.29996",
189
+ stroke: "#808080",
190
+ strokeWidth: "1.33333",
191
+ strokeLinecap: "round",
192
+ strokeLinejoin: "round"
193
+ })
194
+ ]
195
+ });
196
+ const LlmsViewOptions = ({ options = [
197
+ 'markdownLink',
198
+ 'chatgpt',
199
+ 'claude'
200
+ ], text, textByLang = {
201
+ en: 'Open',
202
+ zh: "\u6253\u5F00"
203
+ } })=>{
204
+ const [isOpen, setIsOpen] = useState(false);
205
+ const dropdownRef = useRef(null);
206
+ useEffect(()=>{
207
+ const handleClickOutside = (event)=>{
208
+ if (dropdownRef.current && event.target && !dropdownRef.current.contains(event.target)) setIsOpen(false);
209
+ };
210
+ document.addEventListener('mousedown', handleClickOutside);
211
+ return ()=>{
212
+ document.removeEventListener('mousedown', handleClickOutside);
213
+ };
214
+ }, []);
215
+ const toggleDropdown = ()=>{
216
+ setIsOpen(!isOpen);
217
+ };
218
+ const { pathname } = useMdUrl();
219
+ const lang = useLang();
220
+ const isEn = !lang || 'en' === lang;
221
+ const items = useMemo(()=>{
222
+ const fullMarkdownUrl = 'undefined' != typeof window ? new URL(pathname, window.location.origin).toString() : 'loading';
223
+ const q = `Read ${fullMarkdownUrl}, I want to ask questions about it.`;
224
+ return {
225
+ markdownLink: {
226
+ title: isEn ? 'Copy Markdown link' : "\u590D\u5236 Markdown \u94FE\u63A5",
227
+ icon: /*#__PURE__*/ jsx("svg", {
228
+ xmlns: "http://www.w3.org/2000/svg",
229
+ viewBox: "0 0 24 24",
230
+ width: "24",
231
+ height: "24",
232
+ children: /*#__PURE__*/ jsxs("g", {
233
+ fill: "none",
234
+ stroke: "currentColor",
235
+ strokeLinecap: "round",
236
+ strokeLinejoin: "round",
237
+ strokeWidth: "2",
238
+ children: [
239
+ /*#__PURE__*/ jsx("path", {
240
+ d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"
241
+ }),
242
+ /*#__PURE__*/ jsx("path", {
243
+ d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"
244
+ })
245
+ ]
246
+ })
247
+ }),
248
+ onClick: ()=>{
249
+ navigator.clipboard.writeText(fullMarkdownUrl);
250
+ }
251
+ },
252
+ chatgpt: {
253
+ title: isEn ? 'Open in ChatGPT' : "\u5728 ChatGPT \u4E2D\u6253\u5F00",
254
+ href: `https://chatgpt.com/?${new URLSearchParams({
255
+ hints: 'search',
256
+ q
257
+ })}`,
258
+ icon: /*#__PURE__*/ jsxs("svg", {
259
+ role: "img",
260
+ viewBox: "0 0 24 24",
261
+ fill: "currentColor",
262
+ xmlns: "http://www.w3.org/2000/svg",
263
+ children: [
264
+ /*#__PURE__*/ jsx("title", {
265
+ children: "OpenAI"
266
+ }),
267
+ /*#__PURE__*/ jsx("path", {
268
+ 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"
269
+ })
270
+ ]
271
+ })
272
+ },
273
+ claude: {
274
+ title: isEn ? 'Open in Claude' : "\u5728 Claude \u4E2D\u6253\u5F00",
275
+ href: `https://claude.ai/new?${new URLSearchParams({
276
+ q
277
+ })}`,
278
+ icon: /*#__PURE__*/ jsxs("svg", {
279
+ fill: "currentColor",
280
+ role: "img",
281
+ viewBox: "0 0 24 24",
282
+ xmlns: "http://www.w3.org/2000/svg",
283
+ children: [
284
+ /*#__PURE__*/ jsx("title", {
285
+ children: "Anthropic"
286
+ }),
287
+ /*#__PURE__*/ jsx("path", {
288
+ 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"
289
+ })
290
+ ]
291
+ })
292
+ }
293
+ };
294
+ }, [
295
+ pathname,
296
+ isEn
297
+ ]);
298
+ return /*#__PURE__*/ jsx(Fragment, {
299
+ children: /*#__PURE__*/ jsxs("button", {
300
+ ref: dropdownRef,
301
+ className: [
302
+ LlmsViewOptions_module_3,
303
+ isOpen ? LlmsViewOptions_module_1 : ''
304
+ ].filter(Boolean).join(' '),
305
+ type: "button",
306
+ onClick: toggleDropdown,
307
+ children: [
308
+ text ?? textByLang[lang] ?? 'Open',
309
+ /*#__PURE__*/ jsx(IconArrow, {
310
+ className: `${LlmsViewOptions_module_2} ${isOpen ? _9 : ''}`
311
+ }),
312
+ isOpen && /*#__PURE__*/ jsx("div", {
313
+ className: LlmsViewOptions_module_5,
314
+ children: options.map((item)=>{
315
+ let displayItem = item;
316
+ if ('markdownLink' === item) displayItem = items.markdownLink;
317
+ else if ('chatgpt' === item) displayItem = items.chatgpt;
318
+ else if ('claude' === item) displayItem = items.claude;
319
+ if (displayItem.href) return /*#__PURE__*/ jsxs("a", {
320
+ className: LlmsViewOptions_module_4,
321
+ href: displayItem.href,
322
+ target: "_blank",
323
+ rel: "noopener noreferrer",
324
+ children: [
325
+ /*#__PURE__*/ jsx("span", {
326
+ className: _8,
327
+ children: displayItem.icon
328
+ }),
329
+ /*#__PURE__*/ jsx("span", {
330
+ children: displayItem.title
331
+ }),
332
+ /*#__PURE__*/ jsx("span", {
333
+ className: LlmsViewOptions_module_6,
334
+ children: /*#__PURE__*/ jsx(IconExternalLink, {})
335
+ })
336
+ ]
337
+ }, displayItem.title);
338
+ return /*#__PURE__*/ jsxs("div", {
339
+ className: LlmsViewOptions_module_4,
340
+ onClick: displayItem.onClick,
341
+ children: [
342
+ /*#__PURE__*/ jsx("span", {
343
+ className: _8,
344
+ children: displayItem.icon
345
+ }),
346
+ /*#__PURE__*/ jsx("span", {
347
+ children: displayItem.title
348
+ })
349
+ ]
350
+ }, displayItem.title);
351
+ })
352
+ })
353
+ ]
354
+ })
355
+ });
356
+ };
357
+ 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.3",
3
+ "version": "2.0.0-beta.31",
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.3"
35
+ "unist-util-visit": "^5.0.0"
28
36
  },
29
37
  "devDependencies": {
30
- "@microsoft/api-extractor": "^7.52.5",
31
- "@rsbuild/core": "1.3.13",
32
- "@rslib/core": "0.6.7",
38
+ "@microsoft/api-extractor": "^7.52.11",
39
+ "@rsbuild/core": "~1.5.3",
40
+ "@rsbuild/plugin-react": "~1.4.0",
41
+ "@rsbuild/plugin-sass": "~1.4.0",
42
+ "@rslib/core": "0.12.4",
33
43
  "@types/hast": "^3.0.4",
34
- "@types/node": "^18.11.17",
44
+ "@types/node": "^22.8.1",
45
+ "@types/react": "^19.1.12",
46
+ "react": "^19.1.1",
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.3"
50
+ "@rspress/config": "1.0.0"
39
51
  },
40
52
  "peerDependencies": {
41
- "@rspress/core": "^2.0.0-beta.3"
53
+ "@rspress/core": "^2.0.0-beta.31"
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
- */