@rspress/plugin-rss 2.0.0-beta.2 → 2.0.0-beta.20
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 +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +24 -26
- package/package.json +8 -8
- package/static/global-components/FeedsAnnotations.tsx +3 -3
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
@@ -21,15 +21,14 @@ export declare interface FeedChannel extends PartialPartial<FeedOptions, 'title'
|
|
21
21
|
* to match pages that should be listed in this feed
|
22
22
|
* if RegExp is given, it will match against the route path of each page
|
23
23
|
**/
|
24
|
-
test: RegExp | string | (RegExp | string)[] | ((item: PageIndexInfo
|
24
|
+
test: RegExp | string | (RegExp | string)[] | ((item: PageIndexInfo) => boolean);
|
25
25
|
/**
|
26
26
|
* a function to modify feed item
|
27
27
|
* @param item pre-generated feed item
|
28
28
|
* @param page page data
|
29
|
-
* @param base base path of the rspress site
|
30
29
|
* @returns modified feed item
|
31
30
|
*/
|
32
|
-
item?: (item: FeedItem, page: PageIndexInfo
|
31
|
+
item?: (item: FeedItem, page: PageIndexInfo) => FeedItem | PromiseLike<FeedItem>;
|
33
32
|
/**
|
34
33
|
* feed level output config
|
35
34
|
*/
|
@@ -151,6 +150,6 @@ declare interface ResolvedOutput {
|
|
151
150
|
sorting: (left: FeedItem, right: FeedItem) => number;
|
152
151
|
}
|
153
152
|
|
154
|
-
export declare function testPage(test: FeedChannel['test'], page: PageIndexInfo
|
153
|
+
export declare function testPage(test: FeedChannel['test'], page: PageIndexInfo): boolean;
|
155
154
|
|
156
155
|
export { }
|
package/dist/index.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
import
|
4
|
-
import
|
1
|
+
import node_path, { dirname } from "node:path";
|
2
|
+
import { resolve } from "node:url";
|
3
|
+
import { getIconUrlPath } from "@rspress/shared/node-utils";
|
4
|
+
import { Feed } from "feed";
|
5
|
+
import { promises } from "node:fs";
|
5
6
|
function notNullish(n) {
|
6
7
|
return null != n;
|
7
8
|
}
|
@@ -26,20 +27,20 @@ function sortByDate(l, r) {
|
|
26
27
|
return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);
|
27
28
|
}
|
28
29
|
async function writeFile(path, content) {
|
29
|
-
const dir =
|
30
|
-
await
|
30
|
+
const dir = dirname(path);
|
31
|
+
await promises.mkdir(dir, {
|
31
32
|
mode: 493,
|
32
33
|
recursive: true
|
33
34
|
});
|
34
|
-
return
|
35
|
+
return promises.writeFile(path, content);
|
35
36
|
}
|
36
37
|
function generateFeedItem(page, siteUrl) {
|
37
38
|
const { frontmatter: fm } = page;
|
38
39
|
return {
|
39
|
-
id: selectNonNullishProperty(fm.slug, fm.id, page.
|
40
|
+
id: selectNonNullishProperty(fm.slug, fm.id, page.routePath) || '',
|
40
41
|
title: selectNonNullishProperty(fm.title, page.title) || '',
|
41
42
|
author: toAuthors(fm.author),
|
42
|
-
link:
|
43
|
+
link: resolve(siteUrl, selectNonNullishProperty(fm.permalink, page.routePath)?.replace(/^\//, '') || ''),
|
43
44
|
description: selectNonNullishProperty(fm.description) || '',
|
44
45
|
content: selectNonNullishProperty(fm.summary, page._html) || '',
|
45
46
|
date: toDate(fm.date || fm.published_at),
|
@@ -73,11 +74,11 @@ const PluginName = '@rspress/plugin-rss';
|
|
73
74
|
const PluginComponents = {
|
74
75
|
FeedsAnnotations: '@rspress/plugin-rss/FeedsAnnotations'
|
75
76
|
};
|
76
|
-
function testPage(test, page
|
77
|
-
if (Array.isArray(test)) return test.some((item)=>testPage(item, page
|
78
|
-
if ('function' == typeof test) return test(page
|
77
|
+
function testPage(test, page) {
|
78
|
+
if (Array.isArray(test)) return test.some((item)=>testPage(item, page));
|
79
|
+
if ('function' == typeof test) return test(page);
|
79
80
|
const routePath = page.routePath;
|
80
|
-
const pureRoutePath = `/${routePath
|
81
|
+
const pureRoutePath = `/${routePath}`.replace(/^\/+/, '/');
|
81
82
|
if ('string' == typeof test) return [
|
82
83
|
routePath,
|
83
84
|
pureRoutePath
|
@@ -86,7 +87,7 @@ function testPage(test, page, base = '/') {
|
|
86
87
|
routePath,
|
87
88
|
pureRoutePath
|
88
89
|
].some((path)=>test.test(path));
|
89
|
-
throw new Error('test must be of `RegExp` or `string` or `(page: PageIndexInfo
|
90
|
+
throw new Error('test must be of `RegExp` or `string` or `(page: PageIndexInfo) => boolean`');
|
90
91
|
}
|
91
92
|
function getDefaultFeedOption() {
|
92
93
|
return {
|
@@ -127,7 +128,7 @@ function getOutputInfo({ id, output }, { siteUrl, output: globalOutput }) {
|
|
127
128
|
publicPath,
|
128
129
|
`${dir}/`,
|
129
130
|
filename
|
130
|
-
].reduce((u, part)=>u ?
|
131
|
+
].reduce((u, part)=>u ? resolve(u, part) : part);
|
131
132
|
const sorting = output?.sorting || globalOutput?.sorting || ((l, r)=>sortByDate(l.date, r.date));
|
132
133
|
return {
|
133
134
|
type,
|
@@ -152,7 +153,7 @@ class FeedsSet {
|
|
152
153
|
]).map((options)=>({
|
153
154
|
title: config.title || '',
|
154
155
|
description: config.description || '',
|
155
|
-
favicon: config.icon &&
|
156
|
+
favicon: config.icon && resolve(siteUrl, getIconUrlPath(config.icon)),
|
156
157
|
copyright: config.themeConfig?.footer?.message || '',
|
157
158
|
link: siteUrl,
|
158
159
|
docs: '',
|
@@ -172,10 +173,10 @@ class FeedsSet {
|
|
172
173
|
return this.feeds.slice(0);
|
173
174
|
}
|
174
175
|
}
|
175
|
-
function getRssItems(feeds, page,
|
176
|
-
return Promise.all(feeds.filter((options)=>testPage(options.test, page
|
176
|
+
function getRssItems(feeds, page, siteUrl) {
|
177
|
+
return Promise.all(feeds.filter((options)=>testPage(options.test, page)).map(async (options)=>{
|
177
178
|
const after = options.item || ((feed)=>feed);
|
178
|
-
const item = await after(generateFeedItem(page, siteUrl), page
|
179
|
+
const item = await after(generateFeedItem(page, siteUrl), page);
|
179
180
|
return {
|
180
181
|
...item,
|
181
182
|
channel: options.id
|
@@ -185,7 +186,6 @@ function getRssItems(feeds, page, config, siteUrl) {
|
|
185
186
|
function pluginRss(pluginRssOptions) {
|
186
187
|
const feedsSet = new FeedsSet();
|
187
188
|
let _rssWorkaround = null;
|
188
|
-
let _config;
|
189
189
|
return {
|
190
190
|
name: PluginName,
|
191
191
|
globalUIComponents: Object.values(PluginComponents),
|
@@ -195,13 +195,12 @@ function pluginRss(pluginRssOptions) {
|
|
195
195
|
return;
|
196
196
|
}
|
197
197
|
_rssWorkaround = {};
|
198
|
-
_config = config;
|
199
198
|
feedsSet.set(pluginRssOptions, config);
|
200
199
|
},
|
201
200
|
async extendPageData (pageData) {
|
202
201
|
if (!_rssWorkaround) return;
|
203
|
-
_rssWorkaround[pageData.
|
204
|
-
const feeds = await _rssWorkaround[pageData.
|
202
|
+
_rssWorkaround[pageData.routePath] = _rssWorkaround[pageData.routePath] || getRssItems(feedsSet.get(), pageData, pluginRssOptions.siteUrl);
|
203
|
+
const feeds = await _rssWorkaround[pageData.routePath];
|
205
204
|
const showRssList = new Set(concatArray(pageData.frontmatter['link-rss']));
|
206
205
|
for (const feed of feeds)showRssList.add(feed.channel);
|
207
206
|
pageData.feeds = Array.from(showRssList, (id)=>{
|
@@ -218,17 +217,16 @@ function pluginRss(pluginRssOptions) {
|
|
218
217
|
const items = concatArray(...await Promise.all(Object.values(_rssWorkaround)));
|
219
218
|
const feeds = Object.create(null);
|
220
219
|
for (const { channel, ...item } of items){
|
221
|
-
feeds[channel] = feeds[channel] || new
|
220
|
+
feeds[channel] = feeds[channel] || new Feed(createFeed(feedsSet.get(channel), config));
|
222
221
|
feeds[channel].addItem(item);
|
223
222
|
}
|
224
223
|
for (const [channel, feed] of Object.entries(feeds)){
|
225
224
|
const { output } = feedsSet.get(channel);
|
226
225
|
feed.items.sort(output.sorting);
|
227
|
-
const path =
|
226
|
+
const path = node_path.resolve(config.outDir || 'doc_build', output.dir, output.filename);
|
228
227
|
await writeFile(path, output.getContent(feed));
|
229
228
|
}
|
230
229
|
_rssWorkaround = null;
|
231
|
-
_config = null;
|
232
230
|
}
|
233
231
|
};
|
234
232
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@rspress/plugin-rss",
|
3
|
-
"version": "2.0.0-beta.
|
3
|
+
"version": "2.0.0-beta.20",
|
4
4
|
"description": "A plugin for rss generation for rspress",
|
5
5
|
"bugs": "https://github.com/web-infra-dev/rspress/issues",
|
6
6
|
"repository": {
|
@@ -25,19 +25,19 @@
|
|
25
25
|
],
|
26
26
|
"dependencies": {
|
27
27
|
"feed": "^4.2.2",
|
28
|
-
"@rspress/shared": "2.0.0-beta.
|
28
|
+
"@rspress/shared": "2.0.0-beta.20"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
|
-
"@rslib/core": "0.
|
32
|
-
"@types/node": "^
|
33
|
-
"@types/react": "^
|
31
|
+
"@rslib/core": "0.10.4",
|
32
|
+
"@types/node": "^22.8.1",
|
33
|
+
"@types/react": "^19.1.8",
|
34
34
|
"react": "^19.1.0",
|
35
|
-
"rsbuild-plugin-publint": "^0.3.
|
35
|
+
"rsbuild-plugin-publint": "^0.3.2",
|
36
36
|
"typescript": "^5.8.2",
|
37
|
-
"@rspress/runtime": "2.0.0-beta.
|
37
|
+
"@rspress/runtime": "2.0.0-beta.20"
|
38
38
|
},
|
39
39
|
"peerDependencies": {
|
40
|
-
"rspress": "^2.0.0-beta.
|
40
|
+
"rspress": "^2.0.0-beta.20"
|
41
41
|
},
|
42
42
|
"engines": {
|
43
43
|
"node": ">=18.0.0"
|
@@ -1,14 +1,14 @@
|
|
1
1
|
/// <reference path="../../index.d.ts" />
|
2
2
|
|
3
3
|
import type { LinkHTMLAttributes } from 'react';
|
4
|
-
import {
|
4
|
+
import { Head, usePageData } from 'rspress/runtime';
|
5
5
|
|
6
6
|
export default function FeedsAnnotations() {
|
7
7
|
const { page } = usePageData();
|
8
8
|
const feeds = page.feeds || [];
|
9
9
|
|
10
10
|
return (
|
11
|
-
<
|
11
|
+
<Head>
|
12
12
|
{feeds.map(({ language, url, mime }) => {
|
13
13
|
const props: LinkHTMLAttributes<HTMLLinkElement> = {
|
14
14
|
rel: 'alternate',
|
@@ -21,6 +21,6 @@ export default function FeedsAnnotations() {
|
|
21
21
|
// biome-ignore lint/correctness/useJsxKeyInIterable: no key props
|
22
22
|
return <link {...props} />;
|
23
23
|
})}
|
24
|
-
</
|
24
|
+
</Head>
|
25
25
|
);
|
26
26
|
}
|