@rspress/plugin-rss 2.0.0-beta.9 → 2.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -7
- package/dist/index.js +25 -28
- package/index.d.ts +9 -0
- package/package.json +12 -14
- package/static/global-components/FeedsAnnotations.tsx +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { Author } from 'feed';
|
|
|
2
2
|
import type { Feed } from 'feed';
|
|
3
3
|
import type { FeedOptions } from 'feed';
|
|
4
4
|
import type { Item } from 'feed';
|
|
5
|
-
import type { PageIndexInfo } from '@rspress/
|
|
6
|
-
import type { RspressPlugin } from '@rspress/
|
|
7
|
-
import type { UserConfig } from '@rspress/
|
|
5
|
+
import type { PageIndexInfo } from '@rspress/core';
|
|
6
|
+
import type { RspressPlugin } from '@rspress/core';
|
|
7
|
+
import type { UserConfig } from '@rspress/core';
|
|
8
8
|
|
|
9
9
|
export declare function createFeed(options: Omit<FeedChannel, 'test' | 'item' | 'output'> & {
|
|
10
10
|
item?: unknown;
|
|
@@ -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,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { resolve } from "node:url";
|
|
2
|
+
import { promises } from "node:fs";
|
|
3
|
+
import node_path, { dirname } from "node:path";
|
|
4
|
+
import { getIconUrlPath } from "@rspress/core";
|
|
5
|
+
import { Feed } from "feed";
|
|
6
6
|
function notNullish(n) {
|
|
7
7
|
return null != n;
|
|
8
8
|
}
|
|
@@ -27,20 +27,20 @@ function sortByDate(l, r) {
|
|
|
27
27
|
return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);
|
|
28
28
|
}
|
|
29
29
|
async function writeFile(path, content) {
|
|
30
|
-
const dir =
|
|
31
|
-
await
|
|
30
|
+
const dir = dirname(path);
|
|
31
|
+
await promises.mkdir(dir, {
|
|
32
32
|
mode: 493,
|
|
33
33
|
recursive: true
|
|
34
34
|
});
|
|
35
|
-
return
|
|
35
|
+
return promises.writeFile(path, content);
|
|
36
36
|
}
|
|
37
37
|
function generateFeedItem(page, siteUrl) {
|
|
38
38
|
const { frontmatter: fm } = page;
|
|
39
39
|
return {
|
|
40
|
-
id: selectNonNullishProperty(fm.slug, fm.id, page.
|
|
40
|
+
id: selectNonNullishProperty(fm.slug, fm.id, page.routePath) || '',
|
|
41
41
|
title: selectNonNullishProperty(fm.title, page.title) || '',
|
|
42
42
|
author: toAuthors(fm.author),
|
|
43
|
-
link:
|
|
43
|
+
link: resolve(siteUrl, selectNonNullishProperty(fm.permalink, page.routePath)?.replace(/^\//, '') || ''),
|
|
44
44
|
description: selectNonNullishProperty(fm.description) || '',
|
|
45
45
|
content: selectNonNullishProperty(fm.summary, page._html) || '',
|
|
46
46
|
date: toDate(fm.date || fm.published_at),
|
|
@@ -50,7 +50,7 @@ function generateFeedItem(page, siteUrl) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
function createFeed(options, config) {
|
|
53
|
-
const { output, item, id, title, ..._options } = options;
|
|
53
|
+
const { output, item: _item, id, title, ..._options } = options;
|
|
54
54
|
return {
|
|
55
55
|
id,
|
|
56
56
|
copyright: config.themeConfig?.footer?.message || '',
|
|
@@ -74,11 +74,11 @@ const PluginName = '@rspress/plugin-rss';
|
|
|
74
74
|
const PluginComponents = {
|
|
75
75
|
FeedsAnnotations: '@rspress/plugin-rss/FeedsAnnotations'
|
|
76
76
|
};
|
|
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
|
|
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);
|
|
80
80
|
const routePath = page.routePath;
|
|
81
|
-
const pureRoutePath = `/${routePath
|
|
81
|
+
const pureRoutePath = `/${routePath}`.replace(/^\/+/, '/');
|
|
82
82
|
if ('string' == typeof test) return [
|
|
83
83
|
routePath,
|
|
84
84
|
pureRoutePath
|
|
@@ -87,7 +87,7 @@ function testPage(test, page, base = '/') {
|
|
|
87
87
|
routePath,
|
|
88
88
|
pureRoutePath
|
|
89
89
|
].some((path)=>test.test(path));
|
|
90
|
-
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`');
|
|
91
91
|
}
|
|
92
92
|
function getDefaultFeedOption() {
|
|
93
93
|
return {
|
|
@@ -128,7 +128,7 @@ function getOutputInfo({ id, output }, { siteUrl, output: globalOutput }) {
|
|
|
128
128
|
publicPath,
|
|
129
129
|
`${dir}/`,
|
|
130
130
|
filename
|
|
131
|
-
].reduce((u, part)=>u ?
|
|
131
|
+
].reduce((u, part)=>u ? resolve(u, part) : part);
|
|
132
132
|
const sorting = output?.sorting || globalOutput?.sorting || ((l, r)=>sortByDate(l.date, r.date));
|
|
133
133
|
return {
|
|
134
134
|
type,
|
|
@@ -153,7 +153,7 @@ class FeedsSet {
|
|
|
153
153
|
]).map((options)=>({
|
|
154
154
|
title: config.title || '',
|
|
155
155
|
description: config.description || '',
|
|
156
|
-
favicon: config.icon &&
|
|
156
|
+
favicon: config.icon && resolve(siteUrl, getIconUrlPath(config.icon)),
|
|
157
157
|
copyright: config.themeConfig?.footer?.message || '',
|
|
158
158
|
link: siteUrl,
|
|
159
159
|
docs: '',
|
|
@@ -173,10 +173,10 @@ class FeedsSet {
|
|
|
173
173
|
return this.feeds.slice(0);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
function getRssItems(feeds, page,
|
|
177
|
-
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)=>{
|
|
178
178
|
const after = options.item || ((feed)=>feed);
|
|
179
|
-
const item = await after(generateFeedItem(page, siteUrl), page
|
|
179
|
+
const item = await after(generateFeedItem(page, siteUrl), page);
|
|
180
180
|
return {
|
|
181
181
|
...item,
|
|
182
182
|
channel: options.id
|
|
@@ -186,7 +186,6 @@ function getRssItems(feeds, page, config, siteUrl) {
|
|
|
186
186
|
function pluginRss(pluginRssOptions) {
|
|
187
187
|
const feedsSet = new FeedsSet();
|
|
188
188
|
let _rssWorkaround = null;
|
|
189
|
-
let _config;
|
|
190
189
|
return {
|
|
191
190
|
name: PluginName,
|
|
192
191
|
globalUIComponents: Object.values(PluginComponents),
|
|
@@ -196,13 +195,12 @@ function pluginRss(pluginRssOptions) {
|
|
|
196
195
|
return;
|
|
197
196
|
}
|
|
198
197
|
_rssWorkaround = {};
|
|
199
|
-
_config = config;
|
|
200
198
|
feedsSet.set(pluginRssOptions, config);
|
|
201
199
|
},
|
|
202
200
|
async extendPageData (pageData) {
|
|
203
201
|
if (!_rssWorkaround) return;
|
|
204
|
-
_rssWorkaround[pageData.
|
|
205
|
-
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];
|
|
206
204
|
const showRssList = new Set(concatArray(pageData.frontmatter['link-rss']));
|
|
207
205
|
for (const feed of feeds)showRssList.add(feed.channel);
|
|
208
206
|
pageData.feeds = Array.from(showRssList, (id)=>{
|
|
@@ -219,17 +217,16 @@ function pluginRss(pluginRssOptions) {
|
|
|
219
217
|
const items = concatArray(...await Promise.all(Object.values(_rssWorkaround)));
|
|
220
218
|
const feeds = Object.create(null);
|
|
221
219
|
for (const { channel, ...item } of items){
|
|
222
|
-
feeds[channel] = feeds[channel] || new
|
|
220
|
+
feeds[channel] = feeds[channel] || new Feed(createFeed(feedsSet.get(channel), config));
|
|
223
221
|
feeds[channel].addItem(item);
|
|
224
222
|
}
|
|
225
223
|
for (const [channel, feed] of Object.entries(feeds)){
|
|
226
224
|
const { output } = feedsSet.get(channel);
|
|
227
225
|
feed.items.sort(output.sorting);
|
|
228
|
-
const path =
|
|
226
|
+
const path = node_path.resolve(config.outDir || 'doc_build', output.dir, output.filename);
|
|
229
227
|
await writeFile(path, output.getContent(feed));
|
|
230
228
|
}
|
|
231
229
|
_rssWorkaround = null;
|
|
232
|
-
_config = null;
|
|
233
230
|
}
|
|
234
231
|
};
|
|
235
232
|
}
|
package/index.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rspress/plugin-rss",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc.0",
|
|
4
4
|
"description": "A plugin for rss generation for rspress",
|
|
5
5
|
"bugs": "https://github.com/web-infra-dev/rspress/issues",
|
|
6
6
|
"repository": {
|
|
@@ -12,39 +12,37 @@
|
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"types": "./
|
|
15
|
+
"types": "./index.d.ts",
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
17
|
},
|
|
18
18
|
"./FeedsAnnotations": "./static/global-components/FeedsAnnotations.tsx"
|
|
19
19
|
},
|
|
20
20
|
"module": "./dist/index.js",
|
|
21
|
-
"types": "./
|
|
21
|
+
"types": "./index.d.ts",
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
24
|
-
"static"
|
|
24
|
+
"static",
|
|
25
|
+
"index.d.ts"
|
|
25
26
|
],
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"feed": "^4.2.2"
|
|
28
|
-
"@rspress/shared": "2.0.0-beta.9"
|
|
28
|
+
"feed": "^4.2.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@rslib/core": "0.
|
|
31
|
+
"@rslib/core": "0.16.1",
|
|
32
32
|
"@types/node": "^22.8.1",
|
|
33
|
-
"@types/react": "^
|
|
34
|
-
"react": "^19.
|
|
35
|
-
"rsbuild-plugin-publint": "^0.3.
|
|
36
|
-
"typescript": "^5.8.2"
|
|
37
|
-
"@rspress/runtime": "2.0.0-beta.9"
|
|
33
|
+
"@types/react": "^19.2.2",
|
|
34
|
+
"react": "^19.2.0",
|
|
35
|
+
"rsbuild-plugin-publint": "^0.3.3",
|
|
36
|
+
"typescript": "^5.8.2"
|
|
38
37
|
},
|
|
39
38
|
"peerDependencies": {
|
|
40
|
-
"rspress": "^2.0.0-
|
|
39
|
+
"@rspress/core": "^2.0.0-rc.0"
|
|
41
40
|
},
|
|
42
41
|
"engines": {
|
|
43
42
|
"node": ">=18.0.0"
|
|
44
43
|
},
|
|
45
44
|
"publishConfig": {
|
|
46
45
|
"access": "public",
|
|
47
|
-
"provenance": true,
|
|
48
46
|
"registry": "https://registry.npmjs.org/"
|
|
49
47
|
},
|
|
50
48
|
"scripts": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference path="../../index.d.ts" />
|
|
2
2
|
|
|
3
|
+
import { Head, usePageData } from '@rspress/core/runtime';
|
|
3
4
|
import type { LinkHTMLAttributes } from 'react';
|
|
4
|
-
import { Head, usePageData } from 'rspress/runtime';
|
|
5
5
|
|
|
6
6
|
export default function FeedsAnnotations() {
|
|
7
7
|
const { page } = usePageData();
|
|
@@ -16,10 +16,10 @@ export default function FeedsAnnotations() {
|
|
|
16
16
|
href: url,
|
|
17
17
|
};
|
|
18
18
|
if (language) {
|
|
19
|
-
|
|
19
|
+
// @ts-expect-error FIXME: why not hrefLang? @unhead/react issue
|
|
20
|
+
props.hreflang = language;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
return <link {...props} />;
|
|
22
|
+
return <link {...props} key={`${language}-${url}-${mime}`} />;
|
|
23
23
|
})}
|
|
24
24
|
</Head>
|
|
25
25
|
);
|