@rspress/plugin-rss 1.41.0 → 1.41.2

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.mjs CHANGED
@@ -1,277 +1,242 @@
1
- // src/plugin-rss.ts
2
- import NodePath2 from "path";
3
- import { resolve as resolveUrl3 } from "url";
4
- import { Feed } from "feed";
5
-
6
- // src/exports.ts
7
- var PluginName = "@rspress/plugin-rss";
8
- var PluginComponents = {
9
- FeedsAnnotations: "@rspress/plugin-rss/FeedsAnnotations"
1
+ import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path";
2
+ import * as __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__ from "node:url";
3
+ import * as __WEBPACK_EXTERNAL_MODULE_feed__ from "feed";
4
+ import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs";
5
+ const PluginName = '@rspress/plugin-rss';
6
+ const PluginComponents = {
7
+ FeedsAnnotations: '@rspress/plugin-rss/FeedsAnnotations'
10
8
  };
11
-
12
- // src/feed.ts
13
- import { resolve as resolveUrl } from "url";
14
-
15
- // src/internals/lang.ts
16
9
  function notNullish(n) {
17
- return n !== void 0 && n !== null;
10
+ return null != n;
18
11
  }
19
12
  function concatArray(...arrList) {
20
- return arrList.reduce(
21
- (arr, item) => arr.concat((Array.isArray(item) ? item : [item]).filter(notNullish)),
22
- []
23
- );
13
+ return arrList.reduce((arr, item)=>arr.concat((Array.isArray(item) ? item : [
14
+ item
15
+ ]).filter(notNullish)), []);
24
16
  }
25
17
  function selectNonNullishProperty(...list) {
26
- for (const item of list) {
27
- if (item === "")
28
- return "";
29
- if (item === 0)
30
- return "0";
31
- if (typeof item === "number")
32
- return `${item}`;
33
- if (typeof item === "string")
34
- return item;
35
- }
18
+ for (const item of list){
19
+ if ('' === item) return '';
20
+ if (0 === item) return '0';
21
+ if ('number' == typeof item) return `${item}`;
22
+ if ('string' == typeof item) return item;
23
+ }
36
24
  }
37
25
  function toDate(s) {
38
- const d = new Date(s);
39
- return Number.isNaN(d.getDate()) ? null : d;
26
+ const d = new Date(s);
27
+ return Number.isNaN(d.getDate()) ? null : d;
40
28
  }
41
29
  function sortByDate(l, r) {
42
- return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);
30
+ return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);
43
31
  }
44
-
45
- // src/internals/node.ts
46
- import { promises } from "fs";
47
- import * as NodePath from "path";
48
32
  async function writeFile(path, content) {
49
- const dir = NodePath.dirname(path);
50
- await promises.mkdir(dir, { mode: 493, recursive: true });
51
- return promises.writeFile(path, content);
33
+ const dir = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.dirname(path);
34
+ await __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.promises.mkdir(dir, {
35
+ mode: 493,
36
+ recursive: true
37
+ });
38
+ return __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__.promises.writeFile(path, content);
52
39
  }
53
-
54
- // src/feed.ts
55
40
  function generateFeedItem(page, siteUrl) {
56
- const { frontmatter: fm } = page;
57
- return {
58
- id: selectNonNullishProperty(fm.slug, fm.id, page.id) || "",
59
- title: selectNonNullishProperty(fm.title, page.title) || "",
60
- author: toAuthors(fm.author),
61
- link: resolveUrl(
62
- siteUrl,
63
- selectNonNullishProperty(fm.permalink, page.routePath) || ""
64
- ),
65
- description: selectNonNullishProperty(fm.description) || "",
66
- content: selectNonNullishProperty(fm.summary, page._html) || "",
67
- date: toDate(fm.date || fm.published_at),
68
- category: concatArray(fm.categories, fm.category).map(
69
- (cat) => ({ name: cat })
70
- )
71
- };
41
+ const { frontmatter: fm } = page;
42
+ return {
43
+ id: selectNonNullishProperty(fm.slug, fm.id, page.id) || '',
44
+ title: selectNonNullishProperty(fm.title, page.title) || '',
45
+ author: toAuthors(fm.author),
46
+ link: (0, __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__.resolve)(siteUrl, selectNonNullishProperty(fm.permalink, page.routePath) || ''),
47
+ description: selectNonNullishProperty(fm.description) || '',
48
+ content: selectNonNullishProperty(fm.summary, page._html) || '',
49
+ date: toDate(fm.date || fm.published_at),
50
+ category: concatArray(fm.categories, fm.category).map((cat)=>({
51
+ name: cat
52
+ }))
53
+ };
72
54
  }
73
55
  function createFeed(options, config) {
74
- const { output, item, id, title, ..._options } = options;
75
- return {
76
- id,
77
- copyright: config.themeConfig?.footer?.message || "",
78
- description: config.description || "",
79
- link: output.url,
80
- ..._options,
81
- title: title || config.title || ""
82
- };
56
+ var _config_themeConfig_footer, _config_themeConfig;
57
+ const { output, item, id, title, ..._options } = options;
58
+ return {
59
+ id,
60
+ copyright: (null === (_config_themeConfig = config.themeConfig) || void 0 === _config_themeConfig ? void 0 : null === (_config_themeConfig_footer = _config_themeConfig.footer) || void 0 === _config_themeConfig_footer ? void 0 : _config_themeConfig_footer.message) || '',
61
+ description: config.description || '',
62
+ link: output.url,
63
+ ..._options,
64
+ title: title || config.title || ''
65
+ };
83
66
  }
84
67
  function toAuthors(author) {
85
- const authors = (Array.isArray(author) ? author : [author]).filter(Boolean).map((author2) => ({
86
- // email is mandatory for RSS 2.0.
87
- ...typeof author2 === "string" ? { name: author2 } : author2
88
- }));
89
- return authors.length ? authors : void 0;
68
+ const authors = (Array.isArray(author) ? author : [
69
+ author
70
+ ]).filter(Boolean).map((author)=>({
71
+ ...'string' == typeof author ? {
72
+ name: author
73
+ } : author
74
+ }));
75
+ return authors.length ? authors : void 0;
90
76
  }
91
-
92
- // src/options.ts
93
- import { resolve as resolveUrl2 } from "url";
94
- function testPage(test, page, base = "/") {
95
- if (Array.isArray(test)) {
96
- return test.some((item) => testPage(item, page, base));
97
- }
98
- if (typeof test === "function") {
99
- return test(page, base);
100
- }
101
- const routePath = page.routePath;
102
- const pureRoutePath = `/${routePath.startsWith(base) ? routePath.slice(base.length) : routePath}`.replace(/^\/+/, "/");
103
- if (typeof test === "string") {
104
- return [routePath, pureRoutePath].some((path) => path.startsWith(test));
105
- }
106
- if (test instanceof RegExp) {
107
- return [routePath, pureRoutePath].some((path) => test.test(path));
108
- }
109
- throw new Error(
110
- "test must be of `RegExp` or `string` or `(page: PageIndexInfo, base: string) => boolean`"
111
- );
77
+ function testPage(test, page, base = '/') {
78
+ if (Array.isArray(test)) return test.some((item)=>testPage(item, page, base));
79
+ if ('function' == typeof test) return test(page, base);
80
+ const routePath = page.routePath;
81
+ const pureRoutePath = `/${routePath.startsWith(base) ? routePath.slice(base.length) : routePath}`.replace(/^\/+/, '/');
82
+ if ('string' == typeof test) return [
83
+ routePath,
84
+ pureRoutePath
85
+ ].some((path)=>path.startsWith(test));
86
+ if (test instanceof RegExp) return [
87
+ routePath,
88
+ pureRoutePath
89
+ ].some((path)=>test.test(path));
90
+ throw new Error('test must be of `RegExp` or `string` or `(page: PageIndexInfo, base: string) => boolean`');
112
91
  }
113
92
  function getDefaultFeedOption() {
114
- return { id: "blog", test: "/blog/" };
93
+ return {
94
+ id: 'blog',
95
+ test: '/blog/'
96
+ };
115
97
  }
116
98
  function getFeedFileType(type) {
117
- switch (type) {
118
- case "rss":
119
- return {
120
- extension: "rss",
121
- mime: "application/rss+xml",
122
- getContent: (feed) => feed.rss2()
123
- };
124
- case "json":
125
- return {
126
- extension: "json",
127
- mime: "application/json",
128
- getContent: (feed) => feed.json1()
129
- };
130
- case "atom":
131
- default:
132
- return {
133
- extension: "xml",
134
- mime: "application/atom+xml",
135
- getContent: (feed) => feed.atom1()
136
- };
137
- }
99
+ switch(type){
100
+ case 'rss':
101
+ return {
102
+ extension: 'rss',
103
+ mime: 'application/rss+xml',
104
+ getContent: (feed)=>feed.rss2()
105
+ };
106
+ case 'json':
107
+ return {
108
+ extension: 'json',
109
+ mime: 'application/json',
110
+ getContent: (feed)=>feed.json1()
111
+ };
112
+ case 'atom':
113
+ default:
114
+ return {
115
+ extension: 'xml',
116
+ mime: 'application/atom+xml',
117
+ getContent: (feed)=>feed.atom1()
118
+ };
119
+ }
138
120
  }
139
- function getOutputInfo({ id, output }, {
140
- siteUrl,
141
- output: globalOutput
142
- }) {
143
- const type = output?.type || globalOutput?.type || "atom";
144
- const { extension, mime, getContent } = getFeedFileType(type);
145
- const filename = output?.filename || `${id}.${extension}`;
146
- const dir = output?.dir || globalOutput?.dir || "rss";
147
- const publicPath = output?.publicPath || globalOutput?.publicPath || siteUrl;
148
- const url = [publicPath, `${dir}/`, filename].reduce(
149
- (u, part) => u ? resolveUrl2(u, part) : part
150
- );
151
- const sorting = output?.sorting || globalOutput?.sorting || ((l, r) => sortByDate(l.date, r.date));
152
- return { type, mime, filename, getContent, dir, publicPath, url, sorting };
121
+ function getOutputInfo({ id, output }, { siteUrl, output: globalOutput }) {
122
+ const type = (null == output ? void 0 : output.type) || (null == globalOutput ? void 0 : globalOutput.type) || 'atom';
123
+ const { extension, mime, getContent } = getFeedFileType(type);
124
+ const filename = (null == output ? void 0 : output.filename) || `${id}.${extension}`;
125
+ const dir = (null == output ? void 0 : output.dir) || (null == globalOutput ? void 0 : globalOutput.dir) || 'rss';
126
+ const publicPath = (null == output ? void 0 : output.publicPath) || (null == globalOutput ? void 0 : globalOutput.publicPath) || siteUrl;
127
+ const url = [
128
+ publicPath,
129
+ `${dir}/`,
130
+ filename
131
+ ].reduce((u, part)=>u ? (0, __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__.resolve)(u, part) : part);
132
+ const sorting = (null == output ? void 0 : output.sorting) || (null == globalOutput ? void 0 : globalOutput.sorting) || ((l, r)=>sortByDate(l.date, r.date));
133
+ return {
134
+ type,
135
+ mime,
136
+ filename,
137
+ getContent,
138
+ dir,
139
+ publicPath,
140
+ url,
141
+ sorting
142
+ };
153
143
  }
154
-
155
- // src/plugin-rss.ts
156
- var FeedsSet = class {
157
- constructor() {
158
- this.feeds = [];
159
- this.feedsMapById = /* @__PURE__ */ Object.create(null);
160
- }
161
- set({ feed, output, siteUrl }, config) {
162
- this.feeds = (Array.isArray(feed) ? feed : [{ ...getDefaultFeedOption(), ...feed }]).map((options) => ({
163
- title: config.title || "",
164
- description: config.description || "",
165
- favicon: config.icon && resolveUrl3(siteUrl, config.icon),
166
- copyright: config.themeConfig?.footer?.message || "",
167
- link: siteUrl,
168
- docs: "",
169
- ...options,
170
- output: getOutputInfo(options, { siteUrl, output })
171
- }));
172
- this.feedsMapById = this.feeds.reduce(
173
- (m, f) => ({ ...m, [f.id]: f }),
174
- /* @__PURE__ */ Object.create(null)
175
- );
176
- }
177
- get(id) {
178
- if (id) {
179
- return this.feedsMapById[id] || null;
144
+ class FeedsSet {
145
+ set({ feed, output, siteUrl }, config) {
146
+ this.feeds = (Array.isArray(feed) ? feed : [
147
+ {
148
+ ...getDefaultFeedOption(),
149
+ ...feed
150
+ }
151
+ ]).map((options)=>{
152
+ var _config_themeConfig_footer, _config_themeConfig;
153
+ return {
154
+ title: config.title || '',
155
+ description: config.description || '',
156
+ favicon: config.icon && (0, __WEBPACK_EXTERNAL_MODULE_node_url_e96de089__.resolve)(siteUrl, config.icon),
157
+ copyright: (null === (_config_themeConfig = config.themeConfig) || void 0 === _config_themeConfig ? void 0 : null === (_config_themeConfig_footer = _config_themeConfig.footer) || void 0 === _config_themeConfig_footer ? void 0 : _config_themeConfig_footer.message) || '',
158
+ link: siteUrl,
159
+ docs: '',
160
+ ...options,
161
+ output: getOutputInfo(options, {
162
+ siteUrl,
163
+ output
164
+ })
165
+ };
166
+ });
167
+ this.feedsMapById = this.feeds.reduce((m, f)=>({
168
+ ...m,
169
+ [f.id]: f
170
+ }), Object.create(null));
171
+ }
172
+ get(id) {
173
+ if (id) return this.feedsMapById[id] || null;
174
+ return this.feeds.slice(0);
175
+ }
176
+ constructor(){
177
+ this.feeds = [];
178
+ this.feedsMapById = Object.create(null);
180
179
  }
181
- return this.feeds.slice(0);
182
- }
183
- };
184
- function getRssItems(feeds, page, config, siteUrl) {
185
- return Promise.all(
186
- feeds.filter((options) => testPage(options.test, page, config.base)).map(async (options) => {
187
- const after = options.item || ((feed) => feed);
188
- const item = await after(
189
- generateFeedItem(page, siteUrl),
190
- page,
191
- siteUrl
192
- );
193
- return { ...item, channel: options.id };
194
- })
195
- );
196
180
  }
197
- function pluginRss(pluginRssOptions) {
198
- const feedsSet = new FeedsSet();
199
- let _rssWorkaround = null;
200
- let _config;
201
- return {
202
- name: PluginName,
203
- globalUIComponents: Object.values(PluginComponents),
204
- beforeBuild(config, isProd) {
205
- if (!isProd) {
206
- _rssWorkaround = null;
207
- return;
208
- }
209
- _rssWorkaround = {};
210
- _config = config;
211
- feedsSet.set(pluginRssOptions, config);
212
- },
213
- async extendPageData(_pageData) {
214
- if (!_rssWorkaround)
215
- return;
216
- const pageData = _pageData;
217
- _rssWorkaround[pageData.id] = _rssWorkaround[pageData.id] || getRssItems(
218
- feedsSet.get(),
219
- pageData,
220
- _config,
221
- pluginRssOptions.siteUrl
222
- );
223
- const feeds = await _rssWorkaround[pageData.id];
224
- const showRssList = new Set(
225
- concatArray(pageData.frontmatter["link-rss"])
226
- );
227
- for (const feed of feeds) {
228
- showRssList.add(feed.channel);
229
- }
230
- pageData.feeds = Array.from(showRssList, (id) => {
231
- const { output, language } = feedsSet.get(id);
181
+ function getRssItems(feeds, page, config, siteUrl) {
182
+ return Promise.all(feeds.filter((options)=>testPage(options.test, page, config.base)).map(async (options)=>{
183
+ const after = options.item || ((feed)=>feed);
184
+ const item = await after(generateFeedItem(page, siteUrl), page, siteUrl);
232
185
  return {
233
- url: output.url,
234
- mime: output.mime,
235
- language: language || pageData.lang
186
+ ...item,
187
+ channel: options.id
236
188
  };
237
- });
238
- },
239
- async afterBuild(config) {
240
- if (!_rssWorkaround)
241
- return;
242
- const items = concatArray(
243
- ...await Promise.all(Object.values(_rssWorkaround))
244
- );
245
- const feeds = /* @__PURE__ */ Object.create(null);
246
- for (const { channel, ...item } of items) {
247
- feeds[channel] = feeds[channel] || new Feed(createFeed(feedsSet.get(channel), config));
248
- feeds[channel].addItem(item);
249
- }
250
- for (const [channel, feed] of Object.entries(feeds)) {
251
- const { output } = feedsSet.get(channel);
252
- feed.items.sort(output.sorting);
253
- const path = NodePath2.resolve(
254
- config.outDir || "doc_build",
255
- output.dir,
256
- output.filename
257
- );
258
- await writeFile(path, output.getContent(feed));
259
- }
260
- _rssWorkaround = null;
261
- _config = null;
262
- }
263
- };
189
+ }));
264
190
  }
265
- export {
266
- PluginComponents,
267
- PluginName,
268
- createFeed,
269
- generateFeedItem,
270
- getDefaultFeedOption,
271
- getFeedFileType,
272
- getOutputInfo,
273
- pluginRss,
274
- testPage
275
- };
276
-
277
- //# sourceMappingURL=index.mjs.map
191
+ function pluginRss(pluginRssOptions) {
192
+ const feedsSet = new FeedsSet();
193
+ let _rssWorkaround = null;
194
+ let _config;
195
+ return {
196
+ name: PluginName,
197
+ globalUIComponents: Object.values(PluginComponents),
198
+ beforeBuild (config, isProd) {
199
+ if (!isProd) {
200
+ _rssWorkaround = null;
201
+ return;
202
+ }
203
+ _rssWorkaround = {};
204
+ _config = config;
205
+ feedsSet.set(pluginRssOptions, config);
206
+ },
207
+ async extendPageData (_pageData) {
208
+ if (!_rssWorkaround) return;
209
+ const pageData = _pageData;
210
+ _rssWorkaround[pageData.id] = _rssWorkaround[pageData.id] || getRssItems(feedsSet.get(), pageData, _config, pluginRssOptions.siteUrl);
211
+ const feeds = await _rssWorkaround[pageData.id];
212
+ const showRssList = new Set(concatArray(pageData.frontmatter['link-rss']));
213
+ for (const feed of feeds)showRssList.add(feed.channel);
214
+ pageData.feeds = Array.from(showRssList, (id)=>{
215
+ const { output, language } = feedsSet.get(id);
216
+ return {
217
+ url: output.url,
218
+ mime: output.mime,
219
+ language: language || pageData.lang
220
+ };
221
+ });
222
+ },
223
+ async afterBuild (config) {
224
+ if (!_rssWorkaround) return;
225
+ const items = concatArray(...await Promise.all(Object.values(_rssWorkaround)));
226
+ const feeds = Object.create(null);
227
+ for (const { channel, ...item } of items){
228
+ feeds[channel] = feeds[channel] || new __WEBPACK_EXTERNAL_MODULE_feed__.Feed(createFeed(feedsSet.get(channel), config));
229
+ feeds[channel].addItem(item);
230
+ }
231
+ for (const [channel, feed] of Object.entries(feeds)){
232
+ const { output } = feedsSet.get(channel);
233
+ feed.items.sort(output.sorting);
234
+ const path = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(config.outDir || 'doc_build', output.dir, output.filename);
235
+ await writeFile(path, output.getContent(feed));
236
+ }
237
+ _rssWorkaround = null;
238
+ _config = null;
239
+ }
240
+ };
241
+ }
242
+ export { PluginComponents, PluginName, createFeed, generateFeedItem, getDefaultFeedOption, getFeedFileType, getOutputInfo, pluginRss, testPage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspress/plugin-rss",
3
- "version": "1.41.0",
3
+ "version": "1.41.2",
4
4
  "description": "A plugin for rss generation for rspress",
5
5
  "bugs": "https://github.com/web-infra-dev/rspress/issues",
6
6
  "repository": {
@@ -26,19 +26,19 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "feed": "^4.2.2",
29
- "@rspress/shared": "1.41.0"
29
+ "@rspress/shared": "1.41.2"
30
30
  },
31
31
  "devDependencies": {
32
+ "@rslib/core": "0.4.1",
32
33
  "@types/node": "^18.11.17",
33
34
  "@types/react": "^18.3.18",
34
35
  "react": "^18.3.1",
35
36
  "typescript": "^5.5.3",
36
- "vitest": "2.1.9",
37
- "@rspress/runtime": "1.41.0"
37
+ "@rspress/runtime": "1.41.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "react": ">=17.0.0",
41
- "rspress": "^1.41.0"
41
+ "rspress": "^1.41.2"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=14.17.6"
@@ -50,9 +50,8 @@
50
50
  },
51
51
  "jsnext:source": "./src/index.ts",
52
52
  "scripts": {
53
- "build": "modern build",
54
- "dev": "modern build -w",
55
- "reset": "rimraf ./**/node_modules",
56
- "test": "vitest run --passWithNoTests"
53
+ "build": "rslib build",
54
+ "dev": "rslib build -w",
55
+ "reset": "rimraf ./**/node_modules"
57
56
  }
58
57
  }
@@ -1 +0,0 @@
1
- {"version":3,"mappings":"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","names":["import_node_url","resolveUrl","author","NodePath"],"ignoreList":[],"sources":["../src/index.ts","../src/plugin-rss.ts","../src/exports.ts","../src/feed.ts","../src/internals/lang.ts","../src/internals/node.ts","../src/options.ts"],"sourcesContent":["export * from './plugin-rss';\nexport * from './type';\nexport * from './exports';\nexport * from './options';\nexport * from './feed';\n","import NodePath from 'node:path';\nimport { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo, RspressPlugin, UserConfig } from '@rspress/shared';\nimport { Feed } from 'feed';\nimport { PluginComponents, PluginName } from './exports';\nimport { createFeed, generateFeedItem } from './feed';\n\nimport {\n type PageWithFeeds,\n type ResolvedOutput,\n concatArray,\n writeFile,\n} from './internals';\nimport { getDefaultFeedOption, getOutputInfo, testPage } from './options';\nimport type { FeedChannel, FeedItem, PluginRssOptions } from './type';\n\ntype FeedItemWithChannel = FeedItem & { channel: string };\ntype TransformedFeedChannel = FeedChannel & { output: ResolvedOutput };\n\nclass FeedsSet {\n feeds: TransformedFeedChannel[] = [];\n feedsMapById: Record<string, TransformedFeedChannel> = Object.create(null);\n set({ feed, output, siteUrl }: PluginRssOptions, config: UserConfig) {\n this.feeds = (\n Array.isArray(feed) ? feed : [{ ...getDefaultFeedOption(), ...feed }]\n ).map(options => ({\n title: config.title || '',\n description: config.description || '',\n favicon: config.icon && resolveUrl(siteUrl, config.icon),\n copyright: config.themeConfig?.footer?.message || '',\n link: siteUrl,\n docs: '',\n ...options,\n output: getOutputInfo(options, { siteUrl, output }),\n }));\n\n this.feedsMapById = this.feeds.reduce(\n (m, f) => ({ ...m, [f.id]: f }),\n Object.create(null),\n );\n }\n get(): TransformedFeedChannel[];\n get(id: string): TransformedFeedChannel | null;\n get(id?: string): TransformedFeedChannel[] | TransformedFeedChannel | null {\n if (id) {\n return this.feedsMapById[id] || null;\n }\n return this.feeds.slice(0);\n }\n}\n\nfunction getRssItems(\n feeds: TransformedFeedChannel[],\n page: PageIndexInfo,\n config: UserConfig,\n siteUrl: string,\n): Promise<FeedItemWithChannel[]> {\n return Promise.all(\n feeds\n .filter(options => testPage(options.test, page, config.base))\n .map(async options => {\n const after = options.item || ((feed: FeedItem) => feed);\n const item = await after(\n generateFeedItem(page, siteUrl),\n page,\n siteUrl,\n );\n return { ...item, channel: options.id };\n }),\n );\n}\n\nexport function pluginRss(pluginRssOptions: PluginRssOptions): RspressPlugin {\n const feedsSet = new FeedsSet();\n\n /**\n * workaround for retrieving data of pages in `afterBuild`\n * TODO: get pageData list directly in `afterBuild`\n **/\n let _rssWorkaround: null | Record<\n string,\n PromiseLike<FeedItemWithChannel[]>\n > = null;\n let _config: null | UserConfig;\n\n return {\n name: PluginName,\n globalUIComponents: Object.values(PluginComponents),\n beforeBuild(config, isProd) {\n if (!isProd) {\n _rssWorkaround = null;\n return;\n }\n _rssWorkaround = {};\n _config = config;\n feedsSet.set(pluginRssOptions, config);\n },\n async extendPageData(_pageData) {\n if (!_rssWorkaround) return;\n\n const pageData = _pageData as PageWithFeeds;\n\n // rspress run `extendPageData` for each page\n // - let's cache rss items within a complete rspress build\n _rssWorkaround[pageData.id] =\n _rssWorkaround[pageData.id] ||\n getRssItems(\n feedsSet.get(),\n pageData,\n _config!,\n pluginRssOptions.siteUrl,\n );\n\n const feeds = await _rssWorkaround[pageData.id];\n const showRssList = new Set(\n concatArray(pageData.frontmatter['link-rss'] as string[] | string),\n );\n for (const feed of feeds) {\n showRssList.add(feed.channel);\n }\n\n pageData.feeds = Array.from(showRssList, id => {\n const { output, language } = feedsSet.get(id)!;\n return {\n url: output.url,\n mime: output.mime,\n language: language || pageData.lang,\n };\n });\n },\n async afterBuild(config) {\n if (!_rssWorkaround) return;\n\n const items = concatArray(\n ...(await Promise.all(Object.values(_rssWorkaround))),\n );\n const feeds: Record<string, Feed> = Object.create(null);\n\n for (const { channel, ...item } of items) {\n feeds[channel] =\n feeds[channel] ||\n new Feed(createFeed(feedsSet.get(channel)!, config));\n feeds[channel].addItem(item);\n }\n\n for (const [channel, feed] of Object.entries(feeds)) {\n const { output } = feedsSet.get(channel)!;\n feed.items.sort(output.sorting);\n const path = NodePath.resolve(\n config.outDir || 'doc_build',\n output.dir,\n output.filename,\n );\n await writeFile(path, output.getContent(feed));\n }\n _rssWorkaround = null;\n _config = null;\n },\n };\n}\n","export const PluginName = '@rspress/plugin-rss';\n\nexport const PluginComponents = {\n FeedsAnnotations: '@rspress/plugin-rss/FeedsAnnotations',\n} as const;\n","import { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo, UserConfig } from '@rspress/shared';\nimport type { Author, FeedOptions } from 'feed';\nimport {\n type ResolvedOutput,\n concatArray,\n selectNonNullishProperty,\n toDate,\n} from './internals';\nimport type { FeedChannel, FeedItem } from './type';\n\n/**\n * @public\n * @param page Rspress Page Data\n * @param siteUrl\n */\nexport function generateFeedItem(page: PageIndexInfo, siteUrl: string) {\n const { frontmatter: fm } = page;\n return {\n id: selectNonNullishProperty(fm.slug, fm.id, page.id) || '',\n title: selectNonNullishProperty(fm.title, page.title) || '',\n author: toAuthors(fm.author),\n link: resolveUrl(\n siteUrl,\n selectNonNullishProperty(fm.permalink, page.routePath) || '',\n ),\n description: selectNonNullishProperty(fm.description) || '',\n content: selectNonNullishProperty(fm.summary, page._html) || '',\n date: toDate((fm.date as string) || (fm.published_at as string))!,\n category: concatArray(fm.categories as string[], fm.category as string).map(\n cat => ({ name: cat }),\n ),\n } satisfies FeedItem;\n}\n\nexport function createFeed(\n options: Omit<FeedChannel, 'test' | 'item' | 'output'> & {\n item?: any;\n test?: any;\n output: ResolvedOutput;\n },\n config: UserConfig,\n): FeedOptions {\n const { output, item, id, title, ..._options } = options;\n return {\n id,\n copyright: config.themeConfig?.footer?.message || '',\n description: config.description || '',\n link: output.url,\n ..._options,\n title: title || config.title || '',\n };\n}\n\nfunction toAuthors(author: unknown): Author[] | undefined {\n const authors = (Array.isArray(author) ? author : [author])\n .filter(Boolean)\n .map(author => ({\n // email is mandatory for RSS 2.0.\n ...(typeof author === 'string' ? { name: author } : author),\n }));\n return authors.length ? authors : undefined;\n}\n","export type PartialPartial<T, K extends keyof T> = Partial<Pick<T, K>> &\n Omit<T, K>;\n\nexport type ItemOf<T> = T extends Array<infer K> ? K : never;\n\nexport function notNullish<T>(n: T | undefined | null): n is T {\n return n !== undefined && n !== null;\n}\nexport function concatArray<T>(...arrList: (T[] | T | undefined)[]) {\n return arrList.reduce<T[]>(\n (arr, item) =>\n arr.concat((Array.isArray(item) ? item : [item]).filter(notNullish)),\n [] as T[],\n );\n}\n\nexport function selectNonNullishProperty(...list: unknown[]) {\n for (const item of list) {\n if (item === '') return '';\n if (item === 0) return '0';\n if (typeof item === 'number') return `${item}`;\n if (typeof item === 'string') return item;\n }\n}\n\nexport function toDate(s: string | Date): null | Date {\n const d = new Date(s);\n return Number.isNaN(d.getDate()) ? null : d;\n}\n\nexport function sortByDate(l: null | Date, r: null | Date): number {\n return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);\n}\n","import { promises } from 'node:fs';\nimport * as NodePath from 'node:path';\n\nexport async function writeFile(\n path: string,\n content: Parameters<typeof promises.writeFile>[1],\n) {\n const dir = NodePath.dirname(path);\n await promises.mkdir(dir, { mode: 0o755, recursive: true });\n return promises.writeFile(path, content);\n}\n","import { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo } from '@rspress/shared';\nimport type { Feed } from 'feed';\nimport { type ResolvedOutput, sortByDate } from './internals';\nimport type { FeedChannel, FeedOutputType, PluginRssOptions } from './type';\n\nexport function testPage(\n test: FeedChannel['test'],\n page: PageIndexInfo,\n base = '/',\n): boolean {\n if (Array.isArray(test)) {\n return test.some(item => testPage(item, page, base));\n }\n if (typeof test === 'function') {\n return test(page, base);\n }\n const routePath = page.routePath;\n const pureRoutePath = `/${\n routePath.startsWith(base) ? routePath.slice(base.length) : routePath\n }`.replace(/^\\/+/, '/');\n if (typeof test === 'string') {\n return [routePath, pureRoutePath].some(path => path.startsWith(test));\n }\n if (test instanceof RegExp) {\n return [routePath, pureRoutePath].some(path => test.test(path));\n }\n\n throw new Error(\n 'test must be of `RegExp` or `string` or `(page: PageIndexInfo, base: string) => boolean`',\n );\n}\n\nexport function getDefaultFeedOption() {\n return { id: 'blog', test: '/blog/' } satisfies FeedChannel;\n}\n\nexport function getFeedFileType(type: FeedOutputType) {\n switch (type) {\n case 'rss':\n return {\n extension: 'rss',\n mime: 'application/rss+xml',\n getContent: (feed: Feed) => feed.rss2(),\n };\n case 'json':\n return {\n extension: 'json',\n mime: 'application/json',\n getContent: (feed: Feed) => feed.json1(),\n };\n case 'atom':\n default:\n return {\n extension: 'xml',\n mime: 'application/atom+xml',\n getContent: (feed: Feed) => feed.atom1(),\n };\n }\n}\nexport function getOutputInfo(\n { id, output }: Pick<FeedChannel, 'id' | 'output'>,\n {\n siteUrl,\n output: globalOutput,\n }: Pick<PluginRssOptions, 'output' | 'siteUrl'>,\n): ResolvedOutput {\n const type = output?.type || globalOutput?.type || 'atom';\n const { extension, mime, getContent } = getFeedFileType(type);\n const filename = output?.filename || `${id}.${extension}`;\n const dir = output?.dir || globalOutput?.dir || 'rss';\n const publicPath = output?.publicPath || globalOutput?.publicPath || siteUrl;\n const url = [publicPath, `${dir}/`, filename].reduce((u, part) =>\n u ? resolveUrl(u, part) : part,\n );\n const sorting =\n output?.sorting ||\n globalOutput?.sorting ||\n ((l, r) => sortByDate(l.date, r.date));\n return { type, mime, filename, getContent, dir, publicPath, url, sorting };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"mappings":";AAAA,OAAOA,eAAc;AACrB,SAAS,WAAWC,mBAAkB;AAEtC,SAAS,YAAY;;;ACHd,IAAM,aAAa;AAEnB,IAAM,mBAAmB;AAAA,EAC9B,kBAAkB;AACpB;;;ACJA,SAAS,WAAW,kBAAkB;;;ACK/B,SAAS,WAAc,GAAiC;AAC7D,SAAO,MAAM,UAAa,MAAM;AAClC;AACO,SAAS,eAAkB,SAAkC;AAClE,SAAO,QAAQ;AAAA,IACb,CAAC,KAAK,SACJ,IAAI,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,GAAG,OAAO,UAAU,CAAC;AAAA,IACrE,CAAC;AAAA,EACH;AACF;AAEO,SAAS,4BAA4B,MAAiB;AAC3D,aAAW,QAAQ,MAAM;AACvB,QAAI,SAAS;AAAI,aAAO;AACxB,QAAI,SAAS;AAAG,aAAO;AACvB,QAAI,OAAO,SAAS;AAAU,aAAO,GAAG,IAAI;AAC5C,QAAI,OAAO,SAAS;AAAU,aAAO;AAAA,EACvC;AACF;AAEO,SAAS,OAAO,GAA+B;AACpD,QAAM,IAAI,IAAI,KAAK,CAAC;AACpB,SAAO,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,OAAO;AAC5C;AAEO,SAAS,WAAW,GAAgB,GAAwB;AACjE,UAAQ,IAAI,EAAE,QAAQ,IAAI,MAAM,IAAI,EAAE,QAAQ,IAAI;AACpD;;;AChCA,SAAS,gBAAgB;AACzB,YAAY,cAAc;AAE1B,eAAsB,UACpB,MACA,SACA;AACA,QAAM,MAAe,iBAAQ,IAAI;AACjC,QAAM,SAAS,MAAM,KAAK,EAAE,MAAM,KAAO,WAAW,KAAK,CAAC;AAC1D,SAAO,SAAS,UAAU,MAAM,OAAO;AACzC;;;AFMO,SAAS,iBAAiB,MAAqB,SAAiB;AACrE,QAAM,EAAE,aAAa,GAAG,IAAI;AAC5B,SAAO;AAAA,IACL,IAAI,yBAAyB,GAAG,MAAM,GAAG,IAAI,KAAK,EAAE,KAAK;AAAA,IACzD,OAAO,yBAAyB,GAAG,OAAO,KAAK,KAAK,KAAK;AAAA,IACzD,QAAQ,UAAU,GAAG,MAAM;AAAA,IAC3B,MAAM;AAAA,MACJ;AAAA,MACA,yBAAyB,GAAG,WAAW,KAAK,SAAS,KAAK;AAAA,IAC5D;AAAA,IACA,aAAa,yBAAyB,GAAG,WAAW,KAAK;AAAA,IACzD,SAAS,yBAAyB,GAAG,SAAS,KAAK,KAAK,KAAK;AAAA,IAC7D,MAAM,OAAQ,GAAG,QAAoB,GAAG,YAAuB;AAAA,IAC/D,UAAU,YAAY,GAAG,YAAwB,GAAG,QAAkB,EAAE;AAAA,MACtE,UAAQ,EAAE,MAAM,IAAI;AAAA,IACtB;AAAA,EACF;AACF;AAEO,SAAS,WACd,SAKA,QACa;AACb,QAAM,EAAE,QAAQ,MAAM,IAAI,OAAO,GAAG,SAAS,IAAI;AACjD,SAAO;AAAA,IACL;AAAA,IACA,WAAW,OAAO,aAAa,QAAQ,WAAW;AAAA,IAClD,aAAa,OAAO,eAAe;AAAA,IACnC,MAAM,OAAO;AAAA,IACb,GAAG;AAAA,IACH,OAAO,SAAS,OAAO,SAAS;AAAA,EAClC;AACF;AAEA,SAAS,UAAU,QAAuC;AACxD,QAAM,WAAW,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM,GACtD,OAAO,OAAO,EACd,IAAI,CAAAC,aAAW;AAAA;AAAA,IAEd,GAAI,OAAOA,YAAW,WAAW,EAAE,MAAMA,QAAO,IAAIA;AAAA,EACtD,EAAE;AACJ,SAAO,QAAQ,SAAS,UAAU;AACpC;;;AG9DA,SAAS,WAAWD,mBAAkB;AAM/B,SAAS,SACd,MACA,MACA,OAAO,KACE;AACT,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,KAAK,UAAQ,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,EACrD;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AACA,QAAM,YAAY,KAAK;AACvB,QAAM,gBAAgB,IACpB,UAAU,WAAW,IAAI,IAAI,UAAU,MAAM,KAAK,MAAM,IAAI,SAC9D,GAAG,QAAQ,QAAQ,GAAG;AACtB,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO,CAAC,WAAW,aAAa,EAAE,KAAK,UAAQ,KAAK,WAAW,IAAI,CAAC;AAAA,EACtE;AACA,MAAI,gBAAgB,QAAQ;AAC1B,WAAO,CAAC,WAAW,aAAa,EAAE,KAAK,UAAQ,KAAK,KAAK,IAAI,CAAC;AAAA,EAChE;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,uBAAuB;AACrC,SAAO,EAAE,IAAI,QAAQ,MAAM,SAAS;AACtC;AAEO,SAAS,gBAAgB,MAAsB;AACpD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM;AAAA,QACN,YAAY,CAAC,SAAe,KAAK,KAAK;AAAA,MACxC;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM;AAAA,QACN,YAAY,CAAC,SAAe,KAAK,MAAM;AAAA,MACzC;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO;AAAA,QACL,WAAW;AAAA,QACX,MAAM;AAAA,QACN,YAAY,CAAC,SAAe,KAAK,MAAM;AAAA,MACzC;AAAA,EACJ;AACF;AACO,SAAS,cACd,EAAE,IAAI,OAAO,GACb;AAAA,EACE;AAAA,EACA,QAAQ;AACV,GACgB;AAChB,QAAM,OAAO,QAAQ,QAAQ,cAAc,QAAQ;AACnD,QAAM,EAAE,WAAW,MAAM,WAAW,IAAI,gBAAgB,IAAI;AAC5D,QAAM,WAAW,QAAQ,YAAY,GAAG,EAAE,IAAI,SAAS;AACvD,QAAM,MAAM,QAAQ,OAAO,cAAc,OAAO;AAChD,QAAM,aAAa,QAAQ,cAAc,cAAc,cAAc;AACrE,QAAM,MAAM,CAAC,YAAY,GAAG,GAAG,KAAK,QAAQ,EAAE;AAAA,IAAO,CAAC,GAAG,SACvD,IAAIA,YAAW,GAAG,IAAI,IAAI;AAAA,EAC5B;AACA,QAAM,UACJ,QAAQ,WACR,cAAc,YACb,CAAC,GAAG,MAAM,WAAW,EAAE,MAAM,EAAE,IAAI;AACtC,SAAO,EAAE,MAAM,MAAM,UAAU,YAAY,KAAK,YAAY,KAAK,QAAQ;AAC3E;;;AL7DA,IAAM,WAAN,MAAe;AAAA,EAAf;AACE,iBAAkC,CAAC;AACnC,wBAAuD,uBAAO,OAAO,IAAI;AAAA;AAAA,EACzE,IAAI,EAAE,MAAM,QAAQ,QAAQ,GAAqB,QAAoB;AACnE,SAAK,SACH,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,EAAE,GAAG,qBAAqB,GAAG,GAAG,KAAK,CAAC,GACpE,IAAI,cAAY;AAAA,MAChB,OAAO,OAAO,SAAS;AAAA,MACvB,aAAa,OAAO,eAAe;AAAA,MACnC,SAAS,OAAO,QAAQA,YAAW,SAAS,OAAO,IAAI;AAAA,MACvD,WAAW,OAAO,aAAa,QAAQ,WAAW;AAAA,MAClD,MAAM;AAAA,MACN,MAAM;AAAA,MACN,GAAG;AAAA,MACH,QAAQ,cAAc,SAAS,EAAE,SAAS,OAAO,CAAC;AAAA,IACpD,EAAE;AAEF,SAAK,eAAe,KAAK,MAAM;AAAA,MAC7B,CAAC,GAAG,OAAO,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE;AAAA,MAC7B,uBAAO,OAAO,IAAI;AAAA,IACpB;AAAA,EACF;AAAA,EAGA,IAAI,IAAuE;AACzE,QAAI,IAAI;AACN,aAAO,KAAK,aAAa,EAAE,KAAK;AAAA,IAClC;AACA,WAAO,KAAK,MAAM,MAAM,CAAC;AAAA,EAC3B;AACF;AAEA,SAAS,YACP,OACA,MACA,QACA,SACgC;AAChC,SAAO,QAAQ;AAAA,IACb,MACG,OAAO,aAAW,SAAS,QAAQ,MAAM,MAAM,OAAO,IAAI,CAAC,EAC3D,IAAI,OAAM,YAAW;AACpB,YAAM,QAAQ,QAAQ,SAAS,CAAC,SAAmB;AACnD,YAAM,OAAO,MAAM;AAAA,QACjB,iBAAiB,MAAM,OAAO;AAAA,QAC9B;AAAA,QACA;AAAA,MACF;AACA,aAAO,EAAE,GAAG,MAAM,SAAS,QAAQ,GAAG;AAAA,IACxC,CAAC;AAAA,EACL;AACF;AAEO,SAAS,UAAU,kBAAmD;AAC3E,QAAM,WAAW,IAAI,SAAS;AAM9B,MAAI,iBAGA;AACJ,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,oBAAoB,OAAO,OAAO,gBAAgB;AAAA,IAClD,YAAY,QAAQ,QAAQ;AAC1B,UAAI,CAAC,QAAQ;AACX,yBAAiB;AACjB;AAAA,MACF;AACA,uBAAiB,CAAC;AAClB,gBAAU;AACV,eAAS,IAAI,kBAAkB,MAAM;AAAA,IACvC;AAAA,IACA,MAAM,eAAe,WAAW;AAC9B,UAAI,CAAC;AAAgB;AAErB,YAAM,WAAW;AAIjB,qBAAe,SAAS,EAAE,IACxB,eAAe,SAAS,EAAE,KAC1B;AAAA,QACE,SAAS,IAAI;AAAA,QACb;AAAA,QACA;AAAA,QACA,iBAAiB;AAAA,MACnB;AAEF,YAAM,QAAQ,MAAM,eAAe,SAAS,EAAE;AAC9C,YAAM,cAAc,IAAI;AAAA,QACtB,YAAY,SAAS,YAAY,UAAU,CAAsB;AAAA,MACnE;AACA,iBAAW,QAAQ,OAAO;AACxB,oBAAY,IAAI,KAAK,OAAO;AAAA,MAC9B;AAEA,eAAS,QAAQ,MAAM,KAAK,aAAa,QAAM;AAC7C,cAAM,EAAE,QAAQ,SAAS,IAAI,SAAS,IAAI,EAAE;AAC5C,eAAO;AAAA,UACL,KAAK,OAAO;AAAA,UACZ,MAAM,OAAO;AAAA,UACb,UAAU,YAAY,SAAS;AAAA,QACjC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,MAAM,WAAW,QAAQ;AACvB,UAAI,CAAC;AAAgB;AAErB,YAAM,QAAQ;AAAA,QACZ,GAAI,MAAM,QAAQ,IAAI,OAAO,OAAO,cAAc,CAAC;AAAA,MACrD;AACA,YAAM,QAA8B,uBAAO,OAAO,IAAI;AAEtD,iBAAW,EAAE,SAAS,GAAG,KAAK,KAAK,OAAO;AACxC,cAAM,OAAO,IACX,MAAM,OAAO,KACb,IAAI,KAAK,WAAW,SAAS,IAAI,OAAO,GAAI,MAAM,CAAC;AACrD,cAAM,OAAO,EAAE,QAAQ,IAAI;AAAA,MAC7B;AAEA,iBAAW,CAAC,SAAS,IAAI,KAAK,OAAO,QAAQ,KAAK,GAAG;AACnD,cAAM,EAAE,OAAO,IAAI,SAAS,IAAI,OAAO;AACvC,aAAK,MAAM,KAAK,OAAO,OAAO;AAC9B,cAAM,OAAOD,UAAS;AAAA,UACpB,OAAO,UAAU;AAAA,UACjB,OAAO;AAAA,UACP,OAAO;AAAA,QACT;AACA,cAAM,UAAU,MAAM,OAAO,WAAW,IAAI,CAAC;AAAA,MAC/C;AACA,uBAAiB;AACjB,gBAAU;AAAA,IACZ;AAAA,EACF;AACF","names":["NodePath","resolveUrl","author"],"ignoreList":[],"sources":["../src/plugin-rss.ts","../src/exports.ts","../src/feed.ts","../src/internals/lang.ts","../src/internals/node.ts","../src/options.ts"],"sourcesContent":["import NodePath from 'node:path';\nimport { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo, RspressPlugin, UserConfig } from '@rspress/shared';\nimport { Feed } from 'feed';\nimport { PluginComponents, PluginName } from './exports';\nimport { createFeed, generateFeedItem } from './feed';\n\nimport {\n type PageWithFeeds,\n type ResolvedOutput,\n concatArray,\n writeFile,\n} from './internals';\nimport { getDefaultFeedOption, getOutputInfo, testPage } from './options';\nimport type { FeedChannel, FeedItem, PluginRssOptions } from './type';\n\ntype FeedItemWithChannel = FeedItem & { channel: string };\ntype TransformedFeedChannel = FeedChannel & { output: ResolvedOutput };\n\nclass FeedsSet {\n feeds: TransformedFeedChannel[] = [];\n feedsMapById: Record<string, TransformedFeedChannel> = Object.create(null);\n set({ feed, output, siteUrl }: PluginRssOptions, config: UserConfig) {\n this.feeds = (\n Array.isArray(feed) ? feed : [{ ...getDefaultFeedOption(), ...feed }]\n ).map(options => ({\n title: config.title || '',\n description: config.description || '',\n favicon: config.icon && resolveUrl(siteUrl, config.icon),\n copyright: config.themeConfig?.footer?.message || '',\n link: siteUrl,\n docs: '',\n ...options,\n output: getOutputInfo(options, { siteUrl, output }),\n }));\n\n this.feedsMapById = this.feeds.reduce(\n (m, f) => ({ ...m, [f.id]: f }),\n Object.create(null),\n );\n }\n get(): TransformedFeedChannel[];\n get(id: string): TransformedFeedChannel | null;\n get(id?: string): TransformedFeedChannel[] | TransformedFeedChannel | null {\n if (id) {\n return this.feedsMapById[id] || null;\n }\n return this.feeds.slice(0);\n }\n}\n\nfunction getRssItems(\n feeds: TransformedFeedChannel[],\n page: PageIndexInfo,\n config: UserConfig,\n siteUrl: string,\n): Promise<FeedItemWithChannel[]> {\n return Promise.all(\n feeds\n .filter(options => testPage(options.test, page, config.base))\n .map(async options => {\n const after = options.item || ((feed: FeedItem) => feed);\n const item = await after(\n generateFeedItem(page, siteUrl),\n page,\n siteUrl,\n );\n return { ...item, channel: options.id };\n }),\n );\n}\n\nexport function pluginRss(pluginRssOptions: PluginRssOptions): RspressPlugin {\n const feedsSet = new FeedsSet();\n\n /**\n * workaround for retrieving data of pages in `afterBuild`\n * TODO: get pageData list directly in `afterBuild`\n **/\n let _rssWorkaround: null | Record<\n string,\n PromiseLike<FeedItemWithChannel[]>\n > = null;\n let _config: null | UserConfig;\n\n return {\n name: PluginName,\n globalUIComponents: Object.values(PluginComponents),\n beforeBuild(config, isProd) {\n if (!isProd) {\n _rssWorkaround = null;\n return;\n }\n _rssWorkaround = {};\n _config = config;\n feedsSet.set(pluginRssOptions, config);\n },\n async extendPageData(_pageData) {\n if (!_rssWorkaround) return;\n\n const pageData = _pageData as PageWithFeeds;\n\n // rspress run `extendPageData` for each page\n // - let's cache rss items within a complete rspress build\n _rssWorkaround[pageData.id] =\n _rssWorkaround[pageData.id] ||\n getRssItems(\n feedsSet.get(),\n pageData,\n _config!,\n pluginRssOptions.siteUrl,\n );\n\n const feeds = await _rssWorkaround[pageData.id];\n const showRssList = new Set(\n concatArray(pageData.frontmatter['link-rss'] as string[] | string),\n );\n for (const feed of feeds) {\n showRssList.add(feed.channel);\n }\n\n pageData.feeds = Array.from(showRssList, id => {\n const { output, language } = feedsSet.get(id)!;\n return {\n url: output.url,\n mime: output.mime,\n language: language || pageData.lang,\n };\n });\n },\n async afterBuild(config) {\n if (!_rssWorkaround) return;\n\n const items = concatArray(\n ...(await Promise.all(Object.values(_rssWorkaround))),\n );\n const feeds: Record<string, Feed> = Object.create(null);\n\n for (const { channel, ...item } of items) {\n feeds[channel] =\n feeds[channel] ||\n new Feed(createFeed(feedsSet.get(channel)!, config));\n feeds[channel].addItem(item);\n }\n\n for (const [channel, feed] of Object.entries(feeds)) {\n const { output } = feedsSet.get(channel)!;\n feed.items.sort(output.sorting);\n const path = NodePath.resolve(\n config.outDir || 'doc_build',\n output.dir,\n output.filename,\n );\n await writeFile(path, output.getContent(feed));\n }\n _rssWorkaround = null;\n _config = null;\n },\n };\n}\n","export const PluginName = '@rspress/plugin-rss';\n\nexport const PluginComponents = {\n FeedsAnnotations: '@rspress/plugin-rss/FeedsAnnotations',\n} as const;\n","import { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo, UserConfig } from '@rspress/shared';\nimport type { Author, FeedOptions } from 'feed';\nimport {\n type ResolvedOutput,\n concatArray,\n selectNonNullishProperty,\n toDate,\n} from './internals';\nimport type { FeedChannel, FeedItem } from './type';\n\n/**\n * @public\n * @param page Rspress Page Data\n * @param siteUrl\n */\nexport function generateFeedItem(page: PageIndexInfo, siteUrl: string) {\n const { frontmatter: fm } = page;\n return {\n id: selectNonNullishProperty(fm.slug, fm.id, page.id) || '',\n title: selectNonNullishProperty(fm.title, page.title) || '',\n author: toAuthors(fm.author),\n link: resolveUrl(\n siteUrl,\n selectNonNullishProperty(fm.permalink, page.routePath) || '',\n ),\n description: selectNonNullishProperty(fm.description) || '',\n content: selectNonNullishProperty(fm.summary, page._html) || '',\n date: toDate((fm.date as string) || (fm.published_at as string))!,\n category: concatArray(fm.categories as string[], fm.category as string).map(\n cat => ({ name: cat }),\n ),\n } satisfies FeedItem;\n}\n\nexport function createFeed(\n options: Omit<FeedChannel, 'test' | 'item' | 'output'> & {\n item?: any;\n test?: any;\n output: ResolvedOutput;\n },\n config: UserConfig,\n): FeedOptions {\n const { output, item, id, title, ..._options } = options;\n return {\n id,\n copyright: config.themeConfig?.footer?.message || '',\n description: config.description || '',\n link: output.url,\n ..._options,\n title: title || config.title || '',\n };\n}\n\nfunction toAuthors(author: unknown): Author[] | undefined {\n const authors = (Array.isArray(author) ? author : [author])\n .filter(Boolean)\n .map(author => ({\n // email is mandatory for RSS 2.0.\n ...(typeof author === 'string' ? { name: author } : author),\n }));\n return authors.length ? authors : undefined;\n}\n","export type PartialPartial<T, K extends keyof T> = Partial<Pick<T, K>> &\n Omit<T, K>;\n\nexport type ItemOf<T> = T extends Array<infer K> ? K : never;\n\nexport function notNullish<T>(n: T | undefined | null): n is T {\n return n !== undefined && n !== null;\n}\nexport function concatArray<T>(...arrList: (T[] | T | undefined)[]) {\n return arrList.reduce<T[]>(\n (arr, item) =>\n arr.concat((Array.isArray(item) ? item : [item]).filter(notNullish)),\n [] as T[],\n );\n}\n\nexport function selectNonNullishProperty(...list: unknown[]) {\n for (const item of list) {\n if (item === '') return '';\n if (item === 0) return '0';\n if (typeof item === 'number') return `${item}`;\n if (typeof item === 'string') return item;\n }\n}\n\nexport function toDate(s: string | Date): null | Date {\n const d = new Date(s);\n return Number.isNaN(d.getDate()) ? null : d;\n}\n\nexport function sortByDate(l: null | Date, r: null | Date): number {\n return (r ? r.getTime() : 0) - (l ? l.getTime() : 0);\n}\n","import { promises } from 'node:fs';\nimport * as NodePath from 'node:path';\n\nexport async function writeFile(\n path: string,\n content: Parameters<typeof promises.writeFile>[1],\n) {\n const dir = NodePath.dirname(path);\n await promises.mkdir(dir, { mode: 0o755, recursive: true });\n return promises.writeFile(path, content);\n}\n","import { resolve as resolveUrl } from 'node:url';\nimport type { PageIndexInfo } from '@rspress/shared';\nimport type { Feed } from 'feed';\nimport { type ResolvedOutput, sortByDate } from './internals';\nimport type { FeedChannel, FeedOutputType, PluginRssOptions } from './type';\n\nexport function testPage(\n test: FeedChannel['test'],\n page: PageIndexInfo,\n base = '/',\n): boolean {\n if (Array.isArray(test)) {\n return test.some(item => testPage(item, page, base));\n }\n if (typeof test === 'function') {\n return test(page, base);\n }\n const routePath = page.routePath;\n const pureRoutePath = `/${\n routePath.startsWith(base) ? routePath.slice(base.length) : routePath\n }`.replace(/^\\/+/, '/');\n if (typeof test === 'string') {\n return [routePath, pureRoutePath].some(path => path.startsWith(test));\n }\n if (test instanceof RegExp) {\n return [routePath, pureRoutePath].some(path => test.test(path));\n }\n\n throw new Error(\n 'test must be of `RegExp` or `string` or `(page: PageIndexInfo, base: string) => boolean`',\n );\n}\n\nexport function getDefaultFeedOption() {\n return { id: 'blog', test: '/blog/' } satisfies FeedChannel;\n}\n\nexport function getFeedFileType(type: FeedOutputType) {\n switch (type) {\n case 'rss':\n return {\n extension: 'rss',\n mime: 'application/rss+xml',\n getContent: (feed: Feed) => feed.rss2(),\n };\n case 'json':\n return {\n extension: 'json',\n mime: 'application/json',\n getContent: (feed: Feed) => feed.json1(),\n };\n case 'atom':\n default:\n return {\n extension: 'xml',\n mime: 'application/atom+xml',\n getContent: (feed: Feed) => feed.atom1(),\n };\n }\n}\nexport function getOutputInfo(\n { id, output }: Pick<FeedChannel, 'id' | 'output'>,\n {\n siteUrl,\n output: globalOutput,\n }: Pick<PluginRssOptions, 'output' | 'siteUrl'>,\n): ResolvedOutput {\n const type = output?.type || globalOutput?.type || 'atom';\n const { extension, mime, getContent } = getFeedFileType(type);\n const filename = output?.filename || `${id}.${extension}`;\n const dir = output?.dir || globalOutput?.dir || 'rss';\n const publicPath = output?.publicPath || globalOutput?.publicPath || siteUrl;\n const url = [publicPath, `${dir}/`, filename].reduce((u, part) =>\n u ? resolveUrl(u, part) : part,\n );\n const sorting =\n output?.sorting ||\n globalOutput?.sorting ||\n ((l, r) => sortByDate(l.date, r.date));\n return { type, mime, filename, getContent, dir, publicPath, url, sorting };\n}\n"]}