New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

vuepress-plugin-feed2

Package Overview
Dependencies
Maintainers
1
Versions
307
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vuepress-plugin-feed2 - npm Package Compare versions

Comparing version 2.0.0-beta.7 to 2.0.0-beta.8

20

lib/node/index.d.ts

@@ -341,10 +341,4 @@ import { Page, Plugin, PluginConfig } from '@vuepress/core';

interface FeedOptions {
interface BaseFeedOptions {
/**
* Deploy hostname
*
* 部署的域名
*/
hostname: string;
/**
* Whether to output Atom syntax files.

@@ -446,2 +440,12 @@ *

}
interface FeedOptions extends BaseFeedOptions {
/**
* Deploy hostname
*
* 部署的域名
*/
hostname: string;
/** Locales for feed */
locales?: Record<string, BaseFeedOptions>;
}

@@ -451,2 +455,2 @@ declare const feedPlugin: Plugin<FeedOptions>;

export { FeedAuthor, FeedCategory, FeedChannelOption, FeedContributor, FeedEnclosure, FeedFrontmatterOption, FeedGetter, FeedInitOptions, FeedItemOption, FeedLinks, FeedOptions, FeedPluginFrontmatter, feedPlugin as default, feed, feedPlugin };
export { BaseFeedOptions, FeedAuthor, FeedCategory, FeedChannelOption, FeedContributor, FeedEnclosure, FeedFrontmatterOption, FeedGetter, FeedInitOptions, FeedItemOption, FeedLinks, FeedOptions, FeedPluginFrontmatter, feedPlugin as default, feed, feedPlugin };

2

lib/node/index.js

@@ -1,2 +0,2 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("@mr-hope/vuepress-shared"),e=require("@vuepress/utils"),i=require("path"),r=require("xml-js");function a(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(i){if("default"!==i){var r=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,r.get?r:{enumerable:!0,get:function(){return t[i]}})}})),e.default=t,Object.freeze(e)}var n=a(r);const o=new t.Logger("vuepress-plugin-feed2"),s=(t,e)=>t&&t instanceof Date?e&&e instanceof Date?e.getTime()-t.getTime():-1:1,u=t=>t.replace(/ class=".*?"/gu,"").replace(/ v-pre/gu,"").replace(/<a href="#.*?">.*?<\/a>/gu,"").replace(/(<!--.*?--!?>)|(<!--[\S\s]+?--!?>)|(<!--[\S\s]*?$)/gu,"").replace(/<OutboundLink ?\/>/gu,"").replace(/<RouterLink to="(.*?)">(.*?)<\/RouterLink>/gu,'<a href="$1">$2</a>').replace(/<(?:a|div|span)[^>]*?\/>/gu,"").replace(/<(Badge|FlowChart|Presentation).*?(?:>.*?<\/\1>|\/>)/gu,"<i>Content not supported</i>").replace(/<math[\s\S]*?\/math>/gu,"<i>Content not supported</i>"),p=(t,e="",i="")=>`${t}${e.replace(/^\/?/u,"/").replace(/\/?$/u,"/")}${i.replace(/^\//u,"")}`,c=(t="")=>`image/${"jpg"===t?"jpeg":"svg"===t?"svg+xml":"jpeg"===t||"png"===t||"bmp"===t||"gif"===t||"webp"===t?t:""}`,h=t=>({atomOutputFilename:t.atomOutputFilename||"atom.xml",jsonOutputFilename:t.jsonOutputFilename||"feed.json",rssOutputFilename:t.rssOutputFilename||"rss.xml"}),l=(t,e)=>{const{base:i}=t.options,{hostname:r}=e,{atomOutputFilename:a,jsonOutputFilename:n,rssOutputFilename:o}=h(e);return{atom:p(r,i,a),json:p(r,i,n),rss:p(r,i,o)}},d=e=>{const{name:i,email:r,url:a}=e;return{name:i,...r?{email:r}:{},...a?{uri:t.encodeXML(a)}:{}}},g=t=>{const{name:e,scheme:i}=t;return{_attributes:{term:e,scheme:i}}},m=t=>({name:t.name,...t.url?{url:t.url}:{},...t.avatar?{avatar:t.avatar}:{}}),f=t=>{const{name:e,domain:i}=t;return{_text:e,...i?{_attributes:{domain:i}}:{}}},y=e=>{const i=e.guid||t.encodeXML(e.link);return{...t.isUrl(i)?{}:{_attributes:{isPermaLink:!1}},_text:i}};class b{constructor(e){this.options=e,this.items=[],this.categories=new Set,this._contributorKeys=new Set,this.contributors=[],this.addItem=t=>{this.items.push(t)},this.addCategory=t=>{this.categories.add(t)},this.addContributor=t=>{const e=t.email||t.name;e&&!this._contributorKeys.has(e)&&(this._contributorKeys.add(e),this.contributors.push(t))},this.atom=()=>(e=>{const{channel:i,links:a}=e.options,n={_declaration:{_attributes:{version:"1.0",encoding:"utf-8"}},feed:{_attributes:{xmlns:"http://www.w3.org/2005/Atom",...i.language?{"xml:lang":i.language}:{}},id:i.link,title:i.title,...i.description?{subtitle:i.description}:{},...i.author?{author:d(i.author)}:{},updated:i.lastUpdated?i.lastUpdated.toISOString():(new Date).toISOString(),generator:"vuepress-plugin-feed2",link:[{_attributes:{rel:"self",href:t.encodeXML(a.atom)}}]}};return i.link&&n.feed.link.push({_attributes:{rel:"alternate",href:t.encodeXML(i.link)}}),i.hub&&n.feed.link.push({_attributes:{rel:"hub",href:t.encodeXML(i.hub)}}),i.image&&(n.feed.logo=i.image),i.icon&&(n.feed.icon=i.icon),i.copyright&&(n.feed.rights=i.copyright),n.feed.category=Array.from(e.categories).map((t=>({_attributes:{term:t}}))),n.feed.contributor=Array.from(e.contributors).filter((t=>t.name)).map((t=>d(t))),n.feed.entry=e.items.map((e=>{const i={title:{_attributes:{type:"html"},_text:t.encodeXML(e.title)},id:t.encodeXML(e.guid||e.link),link:{_attributes:{href:t.encodeXML(e.link)}},updated:e.lastUpdated.toISOString()};return e.description&&(i.summary={_attributes:{type:"html"},_cdata:t.encodeCDATA(e.description)}),e.content&&(i.content={_attributes:{type:"html"},_cdata:t.encodeCDATA(e.content)}),Array.isArray(e.author)?i.author=e.author.filter((t=>t.name)).map((t=>d(t))):e.author&&e.author.name&&(i.author=[d(e.author)]),Array.isArray(e.category)?i.category=e.category.map((t=>g(t))):e.category&&(i.category=[g(e.category)]),Array.isArray(e.contributor)&&(i.contributor=e.contributor.map((t=>d(t)))),e.pubDate&&(i.published=e.pubDate.toISOString()),e.copyright&&(i.rights=e.copyright),i})),r.js2xml(n,{compact:!0,ignoreComment:!0,spaces:2})})(this),this.rss=()=>(e=>{const{links:i,channel:r}=e.options;let a=!1;const o={_declaration:{_attributes:{version:"1.0",encoding:"utf-8"}},rss:{_attributes:{version:"2.0","xmlns:atom":"http://www.w3.org/2005/Atom"},channel:{"atom:link":{_attributes:{href:i.rss,rel:"self",type:"application/rss+xml"}},title:{_text:r.title},link:{_text:t.encodeXML(r.link)},description:{_text:r.description},language:{_text:t.encodeXML(r.language)},pubDate:{_text:r.pubDate?r.pubDate.toUTCString():(new Date).toUTCString()},lastBuildDate:{_text:r.lastUpdated?r.lastUpdated.toUTCString():(new Date).toUTCString()},generator:{_text:"vuepress-plugin-feed2"},docs:{_text:"https://validator.w3.org/feed/docs/rss2.html"}}}};return r.copyright&&(o.rss.channel.copyright={_text:r.copyright}),r.ttl&&(o.rss.channel.ttl={_text:r.ttl.toString()}),r.image&&(o.rss.channel.image={title:{_text:r.title},url:{_text:r.image},link:{_text:t.encodeXML(r.link)}}),o.rss.channel.category=Array.from(e.categories).map((t=>({_text:t}))),o.rss.channel.item=e.items.map((e=>{const r={title:{_text:t.encodeXML(e.title)},link:{_text:t.encodeXML(e.link)},guid:y(e),source:{_attributes:{url:i.rss},_text:e.title}};if(e.description&&(r.description={_text:t.encodeXML(e.description)}),Array.isArray(e.author)){const t=e.author.find((t=>t.email&&t.name));t&&(r.author={_text:`${t.email} (${t.name})`})}else if("object"==typeof e.author){const{name:t,email:i}=e.author;i&&t&&(r.author={_text:`${i} (${t})`})}var n;return Array.isArray(e.category)?r.category=e.category.filter((t=>t.name)).map((t=>f(t))):"object"==typeof e.category&&e.category.name&&(r.category=[f(e.category)]),e.comments&&(r.comments={_text:t.encodeXML(e.link)}),e.pubDate&&(r.pubDate={_text:e.pubDate.toUTCString()}),e.content&&(a=!0,r["content:encoded"]={_cdata:t.encodeCDATA(e.content)}),e.enclosure&&(r.enclosure={_attributes:{url:(n=e.enclosure).url,...n.length?{length:n.length}:{},...n.type?{type:n.type}:{}}}),r})),a&&(o.rss._attributes["xmlns:content"]="http://purl.org/rss/1.0/modules/content/",o.rss._attributes["xmlns:dc"]="http://purl.org/dc/elements/1.1/"),n.js2xml(o,{compact:!0,ignoreComment:!0,spaces:2})})(this),this.json=()=>(t=>{var e;const{channel:i,links:r}=t.options,a={version:"https://jsonfeed.org/version/1.1",title:i.title,home_page_url:i.link,feed_url:r.json};return i.description&&(a.description=i.description),i.image&&(a.icon=i.image),i.icon&&(a.favicon=i.icon),(null===(e=i.author)||void 0===e?void 0:e.name)&&(a.author={name:i.author.name,...i.author.url?{url:i.author.url}:{},...i.author.avatar?{avatar:i.author.avatar}:{}}),a.items=t.items.map((t=>{const e={title:t.title,url:t.link,id:t.guid||t.link,...t.description?{summary:t.description}:{},content_html:t.content};return t.image&&(e.image=t.image),t.pubDate&&(e.date_published=t.pubDate.toISOString()),t.lastUpdated&&(e.date_modified=t.lastUpdated.toISOString()),Array.isArray(t.author)?e.authors=t.author.filter((t=>t.name)).map((t=>m(t))):"object"==typeof t.author&&(e.authors=[m(t.author)]),Array.isArray(t.category)?e.tags=t.category.filter((t=>t.name)).map((t=>t.name)):t.category&&(e.tags=[t.category.name]),e})),JSON.stringify(a,null,2)})(this)}}class _{constructor(t,e,i,r){this.app=t,this.options=e,this.page=i,this.feed=r,this.base=this.app.options.base,this.frontmatter=i.frontmatter,this.getter=e.getter||{},this.pageFeedOptions=this.frontmatter.feed||{}}get title(){return"function"==typeof this.getter.title?this.getter.title(this.page):this.pageFeedOptions.title||this.page.title}get link(){return"function"==typeof this.getter.link?this.getter.link(this.page):p(this.options.hostname,this.base,this.page.path)}get description(){return"function"==typeof this.getter.description?this.getter.description(this.page):this.pageFeedOptions.description?this.pageFeedOptions.description:this.frontmatter.description?this.frontmatter.description:this.page.excerpt?u(this.app.markdown.render(this.page.excerpt)):void 0}get author(){var e,i;return"function"==typeof this.getter.author?this.getter.author(this.page):Array.isArray(this.pageFeedOptions.author)?this.pageFeedOptions.author:"object"==typeof this.pageFeedOptions.author?[this.pageFeedOptions.author]:!1===this.frontmatter.author?[]:this.frontmatter.author?t.getAuthor(this.frontmatter.author):(null===(e=this.options.channel)||void 0===e?void 0:e.author)?t.getAuthor(null===(i=this.options.channel)||void 0===i?void 0:i.author):[]}get category(){if("function"==typeof this.getter.category)return this.getter.category(this.page);if(Array.isArray(this.pageFeedOptions.category))return this.pageFeedOptions.category;if("object"==typeof this.pageFeedOptions.category)return[this.pageFeedOptions.category];const{categories:e,category:i=e}=this.frontmatter;return t.getCategory(i).map((t=>({name:t})))}get enclosure(){return"function"==typeof this.getter.enclosure?this.getter.enclosure(this.page):this.image?{url:this.image,type:c(this.image.split(".").pop())}:void 0}get guid(){return this.pageFeedOptions.guid||this.link}get pubDate(){if("function"==typeof this.getter.publishDate)return this.getter.publishDate(this.page);const{time:t,date:e=t}=this.page.frontmatter,{createdTime:i}=this.page.git||{};return e&&e instanceof Date?e:i?new Date(i):void 0}get lastUpdated(){if("function"==typeof this.getter.lastUpdateDate)return this.getter.lastUpdateDate(this.page);const{updatedTime:t}=this.page.git||{};return t?new Date(t):new Date}get content(){return"function"==typeof this.getter.content?this.getter.content(this.page):this.pageFeedOptions.content?this.pageFeedOptions.content:u(this.page.contentRendered)}get image(){if("function"==typeof this.getter.image)return this.getter.image(this.page);const{banner:e,cover:i}=this.frontmatter;if(e){if(t.isAbsoluteUrl(e))return p(this.options.hostname,this.app.options.base,e);if(t.isUrl(e))return e}if(i){if(t.isAbsoluteUrl(i))return p(this.options.hostname,this.app.options.base,i);if(t.isUrl(i))return i}const r=/!\[.*?\]\((.*?)\)/iu.exec(this.page.content);if(r){if(t.isAbsoluteUrl(r[1]))return p(this.options.hostname,this.app.options.base,r[1]);if(t.isUrl(r[1]))return r[1]}}get contributor(){return"function"==typeof this.getter.contributor?this.getter.contributor(this.page):Array.isArray(this.pageFeedOptions.contributor)?this.pageFeedOptions.contributor:"object"==typeof this.pageFeedOptions.contributor?[this.pageFeedOptions.contributor]:this.author}get copyright(){if("function"==typeof this.getter.copyright)return this.getter.copyright(this.page);if(this.frontmatter.copyright)return this.frontmatter.copyright;const t=this.author[0];return t&&t.name?`Copyright by ${t.name}`:void 0}getFeedItem(){const{author:t,category:e,content:i,contributor:r,copyright:a,description:n,enclosure:o,guid:s,image:u,lastUpdated:p,link:c,pubDate:h,title:l}=this;return l||n?(e&&e.forEach((t=>this.feed.addCategory(t.name))),r&&r.forEach((t=>this.feed.addContributor(t))),{title:l,link:c,description:n,author:t,category:e,enclosure:o,guid:s,pubDate:h,lastUpdated:p,content:i,image:u,contributor:r,copyright:a}):null}}class v{constructor(t,e,i,r){this.app=t,this.options=e,this.pages=i,this.feed=new b(r)}addPages(){let t=0;for(const e of this.pages){const i=new _(this.app,this.options,e,this.feed).getFeedItem();i&&(this.feed.addItem(i),t+=1)}o.succeed(`added ${e.chalk.cyan(`${t} page(s)`)} as feed item(s)`)}async generateFeed(){const{dest:t}=this.app.dir,{atomOutputFilename:r,jsonOutputFilename:a,rssOutputFilename:n}=h(this.options);this.addPages(),this.options.atom&&(o.load("Generating Atom Feed"),await e.fs.ensureDir(i.dirname(t(r))),await e.fs.outputFile(t(r),this.feed.atom()),o.update(`Atom feed file generated and saved to ${e.chalk.cyan(r)}`),o.succeed()),this.options.json&&(o.load("Generating JSON Feed"),await e.fs.ensureDir(i.dirname(t(a))),await e.fs.outputFile(t(a),this.feed.json()),o.update(`JSON feed file generated and saved to ${e.chalk.cyan(a)}`),o.succeed()),this.options.rss&&(o.load("Generating RSS Feed"),await e.fs.ensureDir(i.dirname(t(n))),await e.fs.outputFile(t(n),this.feed.rss()),o.update(`RSS feed file generated and saved to ${e.chalk.cyan(n)}`),o.succeed())}}const O=(e,i)=>{if(!e.hostname)return o.error("Option 'hostname' is required!"),{name:"vuepress-plugin-feed2"};e.hostname=e.hostname.replace(/\/?$/u,"");const r=e,a=((e,i)=>{var r,a;const{hostname:n,icon:o,image:s}=i,{base:u}=e.options,{title:c,description:h}=e.siteData,l=null===(a=null===(r=i.channel)||void 0===r?void 0:r.author)||void 0===a?void 0:a.name,d={title:c,link:p(n,u),description:h,language:t.getRootLang(e),copyright:l?`Copyright by ${l}`:"",pubDate:new Date,lastUpdated:new Date,...o?{icon:o}:{},...s?{image:s}:{},...l?{author:{name:l}}:{}};return t.deepAssign(d,i.channel||{})})(i,r);return r.atom||r.json||r.rss?{name:"vuepress-plugin-feed2",onPrepared:t=>((t,e)=>{const{base:i}=t.options,{siteData:r}=t,{atomOutputFilename:a,jsonOutputFilename:n,rssOutputFilename:o}=h(e),s=(t,a,n)=>["link",{rel:"alternate",type:n,href:p(e.hostname,i,a),title:`${r.title||""} ${t} Feed`}];r.head||(r.head=[]),e.atom&&r.head.push(s("Atom",a,"application/atom+xml")),e.json&&r.head.push(s("JSON",n,"application/json")),e.rss&&r.head.push(s("RSS",o,"application/rss+xml"))})(t,r),onGenerated:async t=>{const{filter:e=(({frontmatter:t,filePathRelative:e})=>!(t.home||!e||!1===t.article||!1===t.feed)),sorter:i=((t,e)=>{var i,r,a,n;return s((null===(i=t.git)||void 0===i?void 0:i.createdTime)?new Date(null===(r=t.git)||void 0===r?void 0:r.createdTime):t.frontmatter.date,(null===(a=e.git)||void 0===a?void 0:a.createdTime)?new Date(null===(n=e.git)||void 0===n?void 0:n.createdTime):e.frontmatter.date)})}=r,n=t.pages.filter(e).sort(i).slice(0,r.count||100);await new v(t,r,n,{channel:a,links:l(t,r)}).generateFeed()}}:(o.info("No requested output, the plugin won't start!"),{name:"vuepress-plugin-feed2"})};exports.default=O,exports.feed=t=>["feed2",t],exports.feedPlugin=O;
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("@mr-hope/vuepress-shared"),e=require("@vuepress/utils"),i=require("path"),r=require("xml-js");function a(t){if(t&&t.__esModule)return t;var e=Object.create(null);return t&&Object.keys(t).forEach((function(i){if("default"!==i){var r=Object.getOwnPropertyDescriptor(t,i);Object.defineProperty(e,i,r.get?r:{enumerable:!0,get:function(){return t[i]}})}})),e.default=t,Object.freeze(e)}var o=a(r);const n=new t.Logger("vuepress-plugin-feed2"),s=(t,e)=>t&&t instanceof Date?e&&e instanceof Date?e.getTime()-t.getTime():-1:1,u=t=>t.replace(/ class=".*?"/gu,"").replace(/ v-pre/gu,"").replace(/<a href="#.*?">.*?<\/a>/gu,"").replace(/(<!--.*?--!?>)|(<!--[\S\s]+?--!?>)|(<!--[\S\s]*?$)/gu,"").replace(/<OutboundLink ?\/>/gu,"").replace(/<RouterLink to="(.*?)">(.*?)<\/RouterLink>/gu,'<a href="$1">$2</a>').replace(/<(?:a|div|span)[^>]*?\/>/gu,"").replace(/<(Badge|FlowChart|Presentation).*?(?:>.*?<\/\1>|\/>)/gu,"<i>Content not supported</i>").replace(/<math[\s\S]*?\/math>/gu,"<i>Content not supported</i>"),l=(t,e="",i="")=>`${t}${e.replace(/^\/?/u,"/").replace(/\/?$/u,"/")}${i.replace(/^\//u,"")}`,p=(t="")=>`image/${"jpg"===t?"jpeg":"svg"===t?"svg+xml":"jpeg"===t||"png"===t||"bmp"===t||"gif"===t||"webp"===t?t:""}`,c=(e,i,r="")=>{var a,o,n,s,u,p,c;const{hostname:h,icon:d,image:g}=i,{base:m}=e.options,f=null===(o=null===(a=i.channel)||void 0===a?void 0:a.author)||void 0===o?void 0:o.name,y={title:(null===(n=e.siteData.locales[r])||void 0===n?void 0:n.title)||e.siteData.title||(null===(s=e.siteData.locales["/"])||void 0===s?void 0:s.title)||"",link:l(h,m,r),description:(null===(u=e.siteData.locales[r])||void 0===u?void 0:u.description)||e.siteData.description||(null===(p=e.siteData.locales["/"])||void 0===p?void 0:p.description)||"",language:(null===(c=e.siteData.locales[r])||void 0===c?void 0:c.lang)||e.siteData.lang,copyright:f?`Copyright by ${f}`:"",pubDate:new Date,lastUpdated:new Date,...d?{icon:d}:{},...g?{image:g}:{},...f?{author:{name:f}}:{}};return t.deepAssign(y,i.channel||{})},h=(t,e="/")=>({atomOutputFilename:`${e.replace(/^\//,"")}${t.atomOutputFilename||"atom.xml"}`,jsonOutputFilename:`${e.replace(/^\//,"")}${t.jsonOutputFilename||"feed.json"}`,rssOutputFilename:`${e.replace(/^\//,"")}${t.rssOutputFilename||"rss.xml"}`}),d=(t,e)=>{const{base:i}=t.options,{hostname:r}=e,{atomOutputFilename:a,jsonOutputFilename:o,rssOutputFilename:n}=h(e);return{atom:l(r,i,a),json:l(r,i,o),rss:l(r,i,n)}},g=e=>{const{name:i,email:r,url:a}=e;return{name:i,...r?{email:r}:{},...a?{uri:t.encodeXML(a)}:{}}},m=t=>{const{name:e,scheme:i}=t;return{_attributes:{term:e,scheme:i}}},f=t=>({name:t.name,...t.url?{url:t.url}:{},...t.avatar?{avatar:t.avatar}:{}}),y=t=>{const{name:e,domain:i}=t;return{_text:e,...i?{_attributes:{domain:i}}:{}}},b=e=>{const i=e.guid||t.encodeXML(e.link);return{...t.isUrl(i)?{}:{_attributes:{isPermaLink:!1}},_text:i}};class v{constructor(e){this.options=e,this.items=[],this.categories=new Set,this._contributorKeys=new Set,this.contributors=[],this.addItem=t=>{this.items.push(t)},this.addCategory=t=>{this.categories.add(t)},this.addContributor=t=>{const e=t.email||t.name;e&&!this._contributorKeys.has(e)&&(this._contributorKeys.add(e),this.contributors.push(t))},this.atom=()=>(e=>{const{channel:i,links:a}=e.options,o={_declaration:{_attributes:{version:"1.0",encoding:"utf-8"}},feed:{_attributes:{xmlns:"http://www.w3.org/2005/Atom",...i.language?{"xml:lang":i.language}:{}},id:i.link,title:i.title,...i.description?{subtitle:i.description}:{},...i.author?{author:g(i.author)}:{},updated:i.lastUpdated?i.lastUpdated.toISOString():(new Date).toISOString(),generator:"vuepress-plugin-feed2",link:[{_attributes:{rel:"self",href:t.encodeXML(a.atom)}}]}};return i.link&&o.feed.link.push({_attributes:{rel:"alternate",href:t.encodeXML(i.link)}}),i.hub&&o.feed.link.push({_attributes:{rel:"hub",href:t.encodeXML(i.hub)}}),i.image&&(o.feed.logo=i.image),i.icon&&(o.feed.icon=i.icon),i.copyright&&(o.feed.rights=i.copyright),o.feed.category=Array.from(e.categories).map((t=>({_attributes:{term:t}}))),o.feed.contributor=Array.from(e.contributors).filter((t=>t.name)).map((t=>g(t))),o.feed.entry=e.items.map((e=>{const i={title:{_attributes:{type:"html"},_text:t.encodeXML(e.title)},id:t.encodeXML(e.guid||e.link),link:{_attributes:{href:t.encodeXML(e.link)}},updated:e.lastUpdated.toISOString()};return e.description&&(i.summary=e.description.startsWith("html:")?{_attributes:{type:"html"},_cdata:t.encodeCDATA(e.description.substring(5))}:{_attributes:{type:"html"},_text:e.description}),e.content&&(i.content={_attributes:{type:"html"},_cdata:t.encodeCDATA(e.content)}),Array.isArray(e.author)?i.author=e.author.filter((t=>t.name)).map((t=>g(t))):e.author&&e.author.name&&(i.author=[g(e.author)]),Array.isArray(e.category)?i.category=e.category.map((t=>m(t))):e.category&&(i.category=[m(e.category)]),Array.isArray(e.contributor)&&(i.contributor=e.contributor.map((t=>g(t)))),e.pubDate&&(i.published=e.pubDate.toISOString()),e.copyright&&(i.rights=e.copyright),i})),r.js2xml(o,{compact:!0,ignoreComment:!0,spaces:2})})(this),this.rss=()=>(e=>{const{links:i,channel:r}=e.options;let a=!1;const n={_declaration:{_attributes:{version:"1.0",encoding:"utf-8"}},rss:{_attributes:{version:"2.0","xmlns:atom":"http://www.w3.org/2005/Atom"},channel:{"atom:link":{_attributes:{href:i.rss,rel:"self",type:"application/rss+xml"}},title:{_text:r.title},link:{_text:t.encodeXML(r.link)},description:{_text:r.description},language:{_text:t.encodeXML(r.language)},pubDate:{_text:r.pubDate?r.pubDate.toUTCString():(new Date).toUTCString()},lastBuildDate:{_text:r.lastUpdated?r.lastUpdated.toUTCString():(new Date).toUTCString()},generator:{_text:"vuepress-plugin-feed2"},docs:{_text:"https://validator.w3.org/feed/docs/rss2.html"}}}};return r.copyright&&(n.rss.channel.copyright={_text:r.copyright}),r.ttl&&(n.rss.channel.ttl={_text:r.ttl.toString()}),r.image&&(n.rss.channel.image={title:{_text:r.title},url:{_text:r.image},link:{_text:t.encodeXML(r.link)}}),n.rss.channel.category=Array.from(e.categories).map((t=>({_text:t}))),n.rss.channel.item=e.items.map((e=>{const r={title:{_text:t.encodeXML(e.title)},link:{_text:t.encodeXML(e.link)},guid:b(e),source:{_attributes:{url:i.rss},_text:e.title}};if(e.description&&(r.description={_text:e.description.startsWith("html:")?t.stripTags(e.description.substring(5)):e.description}),Array.isArray(e.author)){const t=e.author.find((t=>t.email&&t.name));t&&(r.author={_text:`${t.email} (${t.name})`})}else if("object"==typeof e.author){const{name:t,email:i}=e.author;i&&t&&(r.author={_text:`${i} (${t})`})}var o;return Array.isArray(e.category)?r.category=e.category.filter((t=>t.name)).map((t=>y(t))):"object"==typeof e.category&&e.category.name&&(r.category=[y(e.category)]),e.comments&&(r.comments={_text:t.encodeXML(e.link)}),e.pubDate&&(r.pubDate={_text:e.pubDate.toUTCString()}),e.content&&(a=!0,r["content:encoded"]={_cdata:t.encodeCDATA(e.content)}),e.enclosure&&(r.enclosure={_attributes:{url:(o=e.enclosure).url,...o.length?{length:o.length}:{},...o.type?{type:o.type}:{}}}),r})),a&&(n.rss._attributes["xmlns:content"]="http://purl.org/rss/1.0/modules/content/",n.rss._attributes["xmlns:dc"]="http://purl.org/dc/elements/1.1/"),o.js2xml(n,{compact:!0,ignoreComment:!0,spaces:2})})(this),this.json=()=>(e=>{var i;const{channel:r,links:a}=e.options,o={version:"https://jsonfeed.org/version/1.1",title:r.title,home_page_url:r.link,feed_url:a.json};return r.description&&(o.description=r.description),r.image&&(o.icon=r.image),r.icon&&(o.favicon=r.icon),(null===(i=r.author)||void 0===i?void 0:i.name)&&(o.author={name:r.author.name,...r.author.url?{url:r.author.url}:{},...r.author.avatar?{avatar:r.author.avatar}:{}}),o.items=e.items.map((e=>{const i={title:e.title,url:e.link,id:e.guid||e.link,...e.description?{summary:e.description.startsWith("html:")?t.stripTags(e.description.substring(5)):e.description}:{},content_html:e.content};return e.image&&(i.image=e.image),e.pubDate&&(i.date_published=e.pubDate.toISOString()),e.lastUpdated&&(i.date_modified=e.lastUpdated.toISOString()),Array.isArray(e.author)?i.authors=e.author.filter((t=>t.name)).map((t=>f(t))):"object"==typeof e.author&&(i.authors=[f(e.author)]),Array.isArray(e.category)?i.tags=e.category.filter((t=>t.name)).map((t=>t.name)):e.category&&(i.tags=[e.category.name]),i})),JSON.stringify(o,null,2)})(this)}}class _{constructor(t,e,i,r){this.app=t,this.options=e,this.page=i,this.feed=r,this.base=this.app.options.base,this.frontmatter=i.frontmatter,this.getter=e.getter||{},this.pageFeedOptions=this.frontmatter.feed||{}}get title(){return"function"==typeof this.getter.title?this.getter.title(this.page):this.pageFeedOptions.title||this.page.title}get link(){return"function"==typeof this.getter.link?this.getter.link(this.page):l(this.options.hostname,this.base,this.page.path)}get description(){return"function"==typeof this.getter.description?this.getter.description(this.page):this.pageFeedOptions.description?this.pageFeedOptions.description:this.frontmatter.description?this.frontmatter.description:this.page.excerpt?`html:${u(this.app.markdown.render(this.page.excerpt))}`:void 0}get author(){var e,i;return"function"==typeof this.getter.author?this.getter.author(this.page):Array.isArray(this.pageFeedOptions.author)?this.pageFeedOptions.author:"object"==typeof this.pageFeedOptions.author?[this.pageFeedOptions.author]:!1===this.frontmatter.author?[]:this.frontmatter.author?t.getAuthor(this.frontmatter.author):(null===(e=this.options.channel)||void 0===e?void 0:e.author)?t.getAuthor(null===(i=this.options.channel)||void 0===i?void 0:i.author):[]}get category(){if("function"==typeof this.getter.category)return this.getter.category(this.page);if(Array.isArray(this.pageFeedOptions.category))return this.pageFeedOptions.category;if("object"==typeof this.pageFeedOptions.category)return[this.pageFeedOptions.category];const{categories:e,category:i=e}=this.frontmatter;return t.getCategory(i).map((t=>({name:t})))}get enclosure(){return"function"==typeof this.getter.enclosure?this.getter.enclosure(this.page):this.image?{url:this.image,type:p(this.image.split(".").pop())}:void 0}get guid(){return this.pageFeedOptions.guid||this.link}get pubDate(){if("function"==typeof this.getter.publishDate)return this.getter.publishDate(this.page);const{time:t,date:e=t}=this.page.frontmatter,{createdTime:i}=this.page.git||{};return e&&e instanceof Date?e:i?new Date(i):void 0}get lastUpdated(){if("function"==typeof this.getter.lastUpdateDate)return this.getter.lastUpdateDate(this.page);const{updatedTime:t}=this.page.git||{};return t?new Date(t):new Date}get content(){return"function"==typeof this.getter.content?this.getter.content(this.page):this.pageFeedOptions.content?this.pageFeedOptions.content:u(this.page.contentRendered)}get image(){if("function"==typeof this.getter.image)return this.getter.image(this.page);const{banner:e,cover:i}=this.frontmatter;if(e){if(t.isAbsoluteUrl(e))return l(this.options.hostname,this.app.options.base,e);if(t.isUrl(e))return e}if(i){if(t.isAbsoluteUrl(i))return l(this.options.hostname,this.app.options.base,i);if(t.isUrl(i))return i}const r=/!\[.*?\]\(.*?\)/iu.exec(this.page.content);if(r){if(t.isAbsoluteUrl(r[1]))return l(this.options.hostname,this.app.options.base,r[1]);if(t.isUrl(r[1]))return r[1]}}get contributor(){return"function"==typeof this.getter.contributor?this.getter.contributor(this.page):Array.isArray(this.pageFeedOptions.contributor)?this.pageFeedOptions.contributor:"object"==typeof this.pageFeedOptions.contributor?[this.pageFeedOptions.contributor]:this.author}get copyright(){if("function"==typeof this.getter.copyright)return this.getter.copyright(this.page);if(this.frontmatter.copyright)return this.frontmatter.copyright;const t=this.author[0];return t&&t.name?`Copyright by ${t.name}`:void 0}getFeedItem(){const{author:t,category:e,content:i,contributor:r,copyright:a,description:o,enclosure:n,guid:s,image:u,lastUpdated:l,link:p,pubDate:c,title:h}=this;return h||o?(e&&e.forEach((t=>this.feed.addCategory(t.name))),r&&r.forEach((t=>this.feed.addContributor(t))),{title:h,link:p,description:o,author:t,category:e,enclosure:n,guid:s,pubDate:c,lastUpdated:l,content:i,image:u,contributor:r,copyright:a}):null}}class O{constructor(t,e){this.app=t,this.options=e,this.feedMap=Object.fromEntries(Object.entries(e).map((([e,i])=>[e,new v({channel:c(t,i,e),links:d(t,i)})])))}addPages(t){const i=this.feedMap[t],r=this.options[t],{filter:a=(({frontmatter:t,filePathRelative:e})=>!(t.home||!e||!1===t.article||!1===t.feed)),sorter:o=((t,e)=>{var i,r,a,o;return s((null===(i=t.git)||void 0===i?void 0:i.createdTime)?new Date(null===(r=t.git)||void 0===r?void 0:r.createdTime):t.frontmatter.date,(null===(a=e.git)||void 0===a?void 0:a.createdTime)?new Date(null===(o=e.git)||void 0===o?void 0:o.createdTime):e.frontmatter.date)})}=r,u=this.app.pages.filter((e=>e.pathLocale===t)).filter(a).sort(o).slice(0,r.count||100);let l=0;for(const t of u){const e=new _(this.app,r,t,i).getFeedItem();e&&(i.addItem(e),l+=1)}n.succeed(`added ${e.chalk.cyan(`${l} page(s)`)} as feed item(s) in route ${e.chalk.cyan(t)}`)}async generateFeed(){const{dest:t}=this.app.dir;await Promise.all(Object.entries(this.options).map((async([r,a])=>{if(a.atom||a.json||a.rss){const o=this.feedMap[r],{atomOutputFilename:s,jsonOutputFilename:u,rssOutputFilename:l}=h(a,r);this.addPages(r),a.atom&&(await e.fs.ensureDir(i.dirname(t(s))),await e.fs.outputFile(t(s),o.atom()),n.succeed(`Atom feed file generated and saved to ${e.chalk.cyan(s)}`)),a.json&&(await e.fs.ensureDir(i.dirname(t(u))),await e.fs.outputFile(t(u),o.json()),n.succeed(`JSON feed file generated and saved to ${e.chalk.cyan(u)}`)),a.rss&&(await e.fs.ensureDir(i.dirname(t(l))),await e.fs.outputFile(t(l),o.rss()),n.succeed(`RSS feed file generated and saved to ${e.chalk.cyan(l)}`))}})))}}const D=(t,e)=>{if(!(t=>!!t.hostname&&(t.hostname=t.hostname.replace(/\/?$/u,""),!0))(t))return n.error("Option 'hostname' is required!"),{name:"vuepress-plugin-feed2"};if(!(t=>t.locales&&Object.entries(t.locales).some((([,{atom:t,json:e,rss:i}])=>t||e||i))||Boolean(t.atom||t.json||t.rss))(t))return n.info("No requested output, the plugin won't start!"),{name:"vuepress-plugin-feed2"};const i=((t,e)=>Object.fromEntries(Object.keys({"/":{},...t.siteData.locales}).map((t=>{var i;return[t,{filter:({frontmatter:t,filePathRelative:e})=>!(t.home||!e||!1===t.article||!1===t.feed),sorter:(t,e)=>{var i,r,a,o;return s((null===(i=t.git)||void 0===i?void 0:i.createdTime)?new Date(null===(r=t.git)||void 0===r?void 0:r.createdTime):t.frontmatter.date,(null===(a=e.git)||void 0===a?void 0:a.createdTime)?new Date(null===(o=e.git)||void 0===o?void 0:o.createdTime):e.frontmatter.date)},...e,...null===(i=e.locales)||void 0===i?void 0:i[t],hostname:e.hostname}]}))))(e,t);return{name:"vuepress-plugin-feed2",onPrepared:t=>((t,e)=>{const{base:i}=t.options,{siteData:r}=t,a=Object.keys(e);if(1===a.length){const{atomOutputFilename:t,jsonOutputFilename:a,rssOutputFilename:o}=h(e["/"]),n=(t,a,o)=>["link",{rel:"alternate",type:o,href:l(e["/"].hostname,i,a),title:`${r.title||r.locales["/"].title||""} ${t} Feed`}];r.head||(r.head=[]),e.atom&&r.head.push(n("Atom",t,"application/atom+xml")),e.json&&r.head.push(n("JSON",a,"application/json")),e.rss&&r.head.push(n("RSS",o,"application/rss+xml"))}else t.pages.forEach((t=>{const{pathLocale:o}=t,n=e[o];if(a.includes(o)){const{atomOutputFilename:e,jsonOutputFilename:a,rssOutputFilename:s}=h(n,o),u=(t,e,a)=>["link",{rel:"alternate",type:a,href:l(n.hostname,i,e),title:`${r.locales[o].title||r.title||r.locales["/"].title||""} ${t} Feed`}];t.frontmatter.head||(t.frontmatter.head=[]),n.atom&&t.frontmatter.head.push(u("Atom",e,"application/atom+xml")),n.json&&t.frontmatter.head.push(u("JSON",a,"application/json")),n.rss&&t.frontmatter.head.push(u("RSS",s,"application/rss+xml"))}}))})(t,i),onGenerated:async t=>{await new O(t,i).generateFeed()}}};exports.default=D,exports.feed=t=>["feed2",t],exports.feedPlugin=D;
//# sourceMappingURL=index.js.map
{
"name": "vuepress-plugin-feed2",
"version": "2.0.0-beta.7",
"version": "2.0.0-beta.8",
"description": "Feed plugin for vuepress-theme-hope",

@@ -44,3 +44,3 @@ "keywords": [

"dependencies": {
"@mr-hope/vuepress-shared": "2.0.0-beta.7",
"@mr-hope/vuepress-shared": "2.0.0-beta.8",
"@vuepress/utils": "2.0.0-beta.35",

@@ -55,3 +55,3 @@ "xml-js": "^1.6.11"

},
"gitHead": "f4cad47182c8a3b9dabb6ae99dcf907c9faec24d"
"gitHead": "646fe86ed1406a1a3f093961289e325c6b1b87f9"
}
import { encodeCDATA, encodeXML } from "@mr-hope/vuepress-shared";
import { js2xml } from "xml-js";
import { generator } from "../utils";
import { FEED_GENERATOR } from "../utils";

@@ -67,3 +67,3 @@ import type { Feed } from "../feed";

: new Date().toISOString(),
generator: generator,
generator: FEED_GENERATOR,
link: [{ _attributes: { rel: "self", href: encodeXML(links.atom) } }],

@@ -110,7 +110,13 @@ },

// entry: recommended elements
if (item.description)
entry.summary = {
_attributes: { type: "html" },
_cdata: encodeCDATA(item.description),
};
if (item.description) {
entry.summary = item.description.startsWith("html:")
? {
_attributes: { type: "html" },
_cdata: encodeCDATA(item.description.substring(5)),
}
: {
_attributes: { type: "html" },
_text: item.description,
};
}

@@ -117,0 +123,0 @@ if (item.content)

@@ -84,3 +84,3 @@ export interface AtomText {

*/
summary?: AtomCDATA;
summary?: AtomText | AtomCDATA;
/**

@@ -87,0 +87,0 @@ * Specifies a category that the entry belongs to.

import { chalk, fs } from "@vuepress/utils";
import { dirname } from "path";
import { getFeedChannelOption, getFilename, getFeedLinks } from "./options";
import { Feed } from "./feed";
import { FeedPage } from "./page";
import { getFilename, logger } from "./utils";
import { compareDate, logger } from "./utils";
import type { App, Page } from "@vuepress/core";
import type { FeedOptions, FeedInitOptions } from "../shared";
import type { GitData } from "@vuepress/plugin-git";
import type { ResolvedFeedOptionsMap } from "./options";
export class FeedGenerator {
/** feed 生成器 */
feed: Feed;
feedMap: Record<string, Feed>;
constructor(
private app: App,
private options: FeedOptions,
private pages: Page[],
feedOption: FeedInitOptions
) {
this.feed = new Feed(feedOption);
constructor(private app: App, private options: ResolvedFeedOptionsMap) {
this.feedMap = Object.fromEntries(
Object.entries(options).map(([localePath, localeOptions]) => {
return [
localePath,
new Feed({
channel: getFeedChannelOption(app, localeOptions, localePath),
links: getFeedLinks(app, localeOptions),
}),
];
})
);
}
addPages(): void {
addPages(localePath: string): void {
const feed = this.feedMap[localePath];
const localeOption = this.options[localePath];
const {
filter = ({ frontmatter, filePathRelative }: Page): boolean =>
!(
frontmatter.home ||
!filePathRelative ||
frontmatter.article === false ||
frontmatter.feed === false
),
sorter = (
pageA: Page<Record<string, never>, { git?: GitData }>,
pageB: Page<Record<string, never>, { git?: GitData }>
): number => {
return compareDate(
pageA.git?.createdTime
? new Date(pageA.git?.createdTime)
: pageA.frontmatter.date,
pageB.git?.createdTime
? new Date(pageB.git?.createdTime)
: pageB.frontmatter.date
);
},
} = localeOption;
const pages = this.app.pages
.filter((page) => page.pathLocale === localePath)
.filter(filter)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
.sort(sorter)
.slice(0, localeOption.count || 100);
let count = 0;
for (const page of this.pages) {
for (const page of pages) {
const item = new FeedPage(
this.app,
this.options,
localeOption,
page,
this.feed
feed
).getFeedItem();
if (item) {
this.feed.addItem(item);
feed.addItem(item);
count += 1;

@@ -40,3 +79,7 @@ }

logger.succeed(`added ${chalk.cyan(`${count} page(s)`)} as feed item(s)`);
logger.succeed(
`added ${chalk.cyan(
`${count} page(s)`
)} as feed item(s) in route ${chalk.cyan(localePath)}`
);
}

@@ -46,50 +89,52 @@

const { dest } = this.app.dir;
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(this.options);
this.addPages();
await Promise.all(
Object.entries(this.options).map(async ([localePath, localeOptions]) => {
// current locale has valid output
if (localeOptions.atom || localeOptions.json || localeOptions.rss) {
const feed = this.feedMap[localePath];
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(localeOptions, localePath);
// generate atom files
if (this.options.atom) {
logger.load("Generating Atom Feed");
this.addPages(localePath);
await fs.ensureDir(dirname(dest(atomOutputFilename)));
await fs.outputFile(dest(atomOutputFilename), this.feed.atom());
// generate atom files
if (localeOptions.atom) {
await fs.ensureDir(dirname(dest(atomOutputFilename)));
await fs.outputFile(dest(atomOutputFilename), feed.atom());
logger.update(
`Atom feed file generated and saved to ${chalk.cyan(
atomOutputFilename
)}`
);
logger.succeed();
}
logger.succeed(
`Atom feed file generated and saved to ${chalk.cyan(
atomOutputFilename
)}`
);
}
// generate json files
if (this.options.json) {
logger.load("Generating JSON Feed");
// generate json files
if (localeOptions.json) {
await fs.ensureDir(dirname(dest(jsonOutputFilename)));
await fs.outputFile(dest(jsonOutputFilename), feed.json());
await fs.ensureDir(dirname(dest(jsonOutputFilename)));
await fs.outputFile(dest(jsonOutputFilename), this.feed.json());
logger.succeed(
`JSON feed file generated and saved to ${chalk.cyan(
jsonOutputFilename
)}`
);
}
logger.update(
`JSON feed file generated and saved to ${chalk.cyan(
jsonOutputFilename
)}`
);
logger.succeed();
}
// generate rss files
if (localeOptions.rss) {
await fs.ensureDir(dirname(dest(rssOutputFilename)));
await fs.outputFile(dest(rssOutputFilename), feed.rss());
// generate rss files
if (this.options.rss) {
logger.load("Generating RSS Feed");
await fs.ensureDir(dirname(dest(rssOutputFilename)));
await fs.outputFile(dest(rssOutputFilename), this.feed.rss());
logger.update(
`RSS feed file generated and saved to ${chalk.cyan(rssOutputFilename)}`
);
logger.succeed();
}
logger.succeed(
`RSS feed file generated and saved to ${chalk.cyan(
rssOutputFilename
)}`
);
}
}
})
);
}
}

@@ -1,47 +0,112 @@

import { getFilename, resolveUrl } from "./utils";
import { getFilename } from "./options";
import { resolveUrl } from "./utils";
import type { App, HeadConfig } from "@vuepress/core";
import type { FeedOptions } from "../shared";
import type { ResolvedFeedOptionsMap } from "./options";
export const injectLinkstoHead = (app: App, options: FeedOptions): void => {
export const injectLinkstoHead = (
app: App,
options: ResolvedFeedOptionsMap
): void => {
const { base } = app.options;
const { siteData } = app;
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(options);
const localePaths = Object.keys(options);
const getHeadItem = (
name: string,
fileName: string,
type: string
): HeadConfig => {
return [
"link",
{
rel: "alternate",
type,
href: resolveUrl(options.hostname, base, fileName),
title: `${siteData.title || ""} ${name} Feed`,
},
];
};
// there is only one language, so we append it to siteData
if (localePaths.length === 1) {
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(options["/"]);
if (!siteData.head) siteData.head = [];
const getHeadItem = (
name: string,
fileName: string,
type: string
): HeadConfig => {
return [
"link",
{
rel: "alternate",
type,
href: resolveUrl(options["/"].hostname, base, fileName),
title: `${
siteData.title || siteData.locales["/"].title || ""
} ${name} Feed`,
},
];
};
// add atom link
if (options.atom)
siteData.head.push(
getHeadItem("Atom", atomOutputFilename, "application/atom+xml")
);
// ensure head exists
if (!siteData.head) siteData.head = [];
// add json link
if (options.json)
siteData.head.push(
getHeadItem("JSON", jsonOutputFilename, "application/json")
);
// add atom link
if (options.atom)
siteData.head.push(
getHeadItem("Atom", atomOutputFilename, "application/atom+xml")
);
// add rss link
if (options.rss)
siteData.head.push(
getHeadItem("RSS", rssOutputFilename, "application/rss+xml")
);
// add json link
if (options.json)
siteData.head.push(
getHeadItem("JSON", jsonOutputFilename, "application/json")
);
// add rss link
if (options.rss)
siteData.head.push(
getHeadItem("RSS", rssOutputFilename, "application/rss+xml")
);
}
// there are mutiple languages, so we should append to page
else
app.pages.forEach((page) => {
const { pathLocale } = page;
const localeOptions = options[pathLocale];
if (localePaths.includes(pathLocale)) {
const { atomOutputFilename, jsonOutputFilename, rssOutputFilename } =
getFilename(localeOptions, pathLocale);
const getHeadItem = (
name: string,
fileName: string,
type: string
): HeadConfig => {
return [
"link",
{
rel: "alternate",
type,
href: resolveUrl(localeOptions.hostname, base, fileName),
title: `${
siteData.locales[pathLocale].title ||
siteData.title ||
siteData.locales["/"].title ||
""
} ${name} Feed`,
},
];
};
// ensure head exists
if (!page.frontmatter.head) page.frontmatter.head = [];
// add atom link
if (localeOptions.atom)
page.frontmatter.head.push(
getHeadItem("Atom", atomOutputFilename, "application/atom+xml")
);
// add json link
if (localeOptions.json)
page.frontmatter.head.push(
getHeadItem("JSON", jsonOutputFilename, "application/json")
);
// add rss link
if (localeOptions.rss)
page.frontmatter.head.push(
getHeadItem("RSS", rssOutputFilename, "application/rss+xml")
);
}
});
};
/* eslint-disable @typescript-eslint/naming-convention */
import { stripTags } from "@mr-hope/vuepress-shared";
import type { Feed } from "../feed";

@@ -45,3 +47,9 @@ import type { FeedAuthor } from "../../shared";

id: item.guid || item.link,
...(item.description ? { summary: item.description } : {}),
...(item.description
? {
summary: item.description.startsWith("html:")
? stripTags(item.description.substring(5))
: item.description,
}
: {}),

@@ -48,0 +56,0 @@ // json_feed distinguishes between html and text content

@@ -1,21 +0,104 @@

import { deepAssign, getRootLang } from "@mr-hope/vuepress-shared";
import { getFilename, resolveUrl } from "./utils";
import { deepAssign } from "@mr-hope/vuepress-shared";
import { compareDate, resolveUrl } from "./utils";
import type { App } from "@vuepress/core";
import type { FeedChannelOption, FeedLinks, FeedOptions } from "../shared";
import type { App, Page } from "@vuepress/core";
import type { GitData } from "@vuepress/plugin-git";
import type {
BaseFeedOptions,
FeedChannelOption,
FeedLinks,
FeedOptions,
} from "../shared";
export type ResolvedFeedOptions = BaseFeedOptions & { hostname: string };
export type ResolvedFeedOptionsMap = Record<string, ResolvedFeedOptions>;
export const ensureHostName = (options: Partial<FeedOptions>): boolean => {
// make sure hostname do not end with `/`
if (options.hostname) {
options.hostname = options.hostname.replace(/\/?$/u, "");
return true;
}
return false;
};
export const checkOutput = (options: Partial<FeedOptions>): boolean =>
// some locales request output
(options.locales &&
Object.entries(options.locales).some(
([, { atom, json, rss }]) => atom || json || rss
)) ||
// root option requsts output
Boolean(options.atom || options.json || options.rss);
export const getFeedOptions = (
app: App,
options: FeedOptions
): ResolvedFeedOptionsMap =>
Object.fromEntries(
Object.keys({
// root locale must exists
"/": {},
...app.siteData.locales,
}).map((localePath) => {
return [
localePath,
{
// default values
filter: ({ frontmatter, filePathRelative }: Page): boolean =>
!(
frontmatter.home ||
!filePathRelative ||
frontmatter.article === false ||
frontmatter.feed === false
),
sorter: (
pageA: Page<Record<string, never>, { git?: GitData }>,
pageB: Page<Record<string, never>, { git?: GitData }>
): number => {
return compareDate(
pageA.git?.createdTime
? new Date(pageA.git?.createdTime)
: pageA.frontmatter.date,
pageB.git?.createdTime
? new Date(pageB.git?.createdTime)
: pageB.frontmatter.date
);
},
...options,
...options.locales?.[localePath],
// make sure hostname is not been overided
hostname: options.hostname,
} as ResolvedFeedOptions,
];
})
);
export const getFeedChannelOption = (
app: App,
options: FeedOptions
options: FeedOptions,
localePath = ""
): FeedChannelOption => {
const { hostname, icon, image } = options;
const { base } = app.options;
const { title, description } = app.siteData;
const author = options.channel?.author?.name;
const defaultChannelOpion: FeedChannelOption = {
title,
link: resolveUrl(hostname, base),
description,
language: getRootLang(app),
title:
app.siteData.locales[localePath]?.title ||
app.siteData.title ||
app.siteData.locales["/"]?.title ||
"",
link: resolveUrl(hostname, base, localePath),
description:
app.siteData.locales[localePath]?.description ||
app.siteData.description ||
app.siteData.locales["/"]?.description ||
"",
language: app.siteData.locales[localePath]?.lang || app.siteData.lang,
copyright: author ? `Copyright by ${author}` : "",

@@ -26,9 +109,3 @@ pubDate: new Date(),

...(image ? { image } : {}),
...(author
? {
author: {
name: author,
},
}
: {}),
...(author ? { author: { name: author } } : {}),
};

@@ -39,2 +116,21 @@

export const getFilename = (
options: ResolvedFeedOptions,
prefix = "/"
): {
atomOutputFilename: string;
jsonOutputFilename: string;
rssOutputFilename: string;
} => ({
atomOutputFilename: `${prefix.replace(/^\//, "")}${
options.atomOutputFilename || "atom.xml"
}`,
jsonOutputFilename: `${prefix.replace(/^\//, "")}${
options.jsonOutputFilename || "feed.json"
}`,
rssOutputFilename: `${prefix.replace(/^\//, "")}${
options.rssOutputFilename || "rss.xml"
}`,
});
export const getFeedLinks = (app: App, options: FeedOptions): FeedLinks => {

@@ -41,0 +137,0 @@ const { base } = app.options;

@@ -69,3 +69,3 @@ import {

if (this.page.excerpt)
return resolveHTML(this.app.markdown.render(this.page.excerpt));
return `html:${resolveHTML(this.app.markdown.render(this.page.excerpt))}`;

@@ -179,3 +179,3 @@ return undefined;

const result = /!\[.*?\]\((.*?)\)/iu.exec(this.page.content);
const result = /!\[.*?\]\(.*?\)/iu.exec(this.page.content);

@@ -182,0 +182,0 @@ if (result) {

@@ -1,15 +0,11 @@

import { getFeedChannelOption, getFeedLinks } from "./options";
import { checkOutput, ensureHostName, getFeedOptions } from "./options";
import { injectLinkstoHead } from "./injectHead";
import { FeedGenerator } from "./generator";
import { compareDate, logger } from "./utils";
import { logger } from "./utils";
import type { Page, Plugin, PluginConfig } from "@vuepress/core";
import type { GitData } from "@vuepress/plugin-git";
import type { Plugin, PluginConfig } from "@vuepress/core";
import type { FeedOptions } from "../shared";
export const feedPlugin: Plugin<FeedOptions> = (options, app) => {
// make sure hostname do not end with `/`
if (options.hostname)
options.hostname = options.hostname.replace(/\/?$/u, "");
else {
if (!ensureHostName(options)) {
logger.error("Option 'hostname' is required!");

@@ -22,6 +18,3 @@

const feedOptions = options as FeedOptions;
const channelOptions = getFeedChannelOption(app, feedOptions);
if (!feedOptions.atom && !feedOptions.json && !feedOptions.rss) {
if (!checkOutput(options)) {
logger.info("No requested output, the plugin won't start!");

@@ -34,2 +27,4 @@

const feedOptions = getFeedOptions(app, options as FeedOptions);
return {

@@ -41,36 +36,3 @@ name: "vuepress-plugin-feed2",

onGenerated: async (app): Promise<void> => {
const {
filter = ({ frontmatter, filePathRelative }: Page): boolean =>
!(
frontmatter.home ||
!filePathRelative ||
frontmatter.article === false ||
frontmatter.feed === false
),
sorter = (
pageA: Page<Record<string, never>, { git?: GitData }>,
pageB: Page<Record<string, never>, { git?: GitData }>
): number => {
return compareDate(
pageA.git?.createdTime
? new Date(pageA.git?.createdTime)
: pageA.frontmatter.date,
pageB.git?.createdTime
? new Date(pageB.git?.createdTime)
: pageB.frontmatter.date
);
},
} = feedOptions;
const feedPages = app.pages
.filter(filter)
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
.sort(sorter)
.slice(0, feedOptions.count || 100);
await new FeedGenerator(app, feedOptions, feedPages, {
channel: channelOptions,
links: getFeedLinks(app, feedOptions),
}).generateFeed();
await new FeedGenerator(app, feedOptions).generateFeed();
},

@@ -77,0 +39,0 @@ };

@@ -0,4 +1,5 @@

import { stripTags } from "@mr-hope/vuepress-shared";
import { encodeCDATA, encodeXML, isUrl } from "@mr-hope/vuepress-shared";
import * as convert from "xml-js";
import { generator } from "../utils";
import { FEED_GENERATOR } from "../utils";

@@ -94,3 +95,3 @@ import type { Feed } from "../feed";

},
generator: { _text: generator },
generator: { _text: FEED_GENERATOR },
docs: {

@@ -141,3 +142,7 @@ _text: "https://validator.w3.org/feed/docs/rss2.html",

if (entry.description)
item.description = { _text: encodeXML(entry.description) };
item.description = {
_text: entry.description.startsWith("html:")
? stripTags(entry.description.substring(5))
: entry.description,
};

@@ -144,0 +149,0 @@ /**

import { Logger } from "@mr-hope/vuepress-shared";
import type { FeedOptions } from "../shared";
export const logger = new Logger("vuepress-plugin-feed2");

@@ -68,15 +66,2 @@

export const getFilename = (
options: FeedOptions
): {
atomOutputFilename: string;
jsonOutputFilename: string;
rssOutputFilename: string;
} => ({
atomOutputFilename: options.atomOutputFilename || "atom.xml",
jsonOutputFilename: options.jsonOutputFilename || "feed.json",
rssOutputFilename: options.rssOutputFilename || "rss.xml",
});
export const generator = "vuepress-plugin-feed2";
export const FEED_GENERATOR = "vuepress-plugin-feed2";
import type { Page } from "@vuepress/core";
import type { FeedChannelOption, FeedGetter } from "./feed";
export interface FeedOptions {
export interface BaseFeedOptions {
/**
* Deploy hostname
*
* 部署的域名
*/
hostname: string;
/**
* Whether to output Atom syntax files.

@@ -121,1 +114,13 @@ *

}
export interface FeedOptions extends BaseFeedOptions {
/**
* Deploy hostname
*
* 部署的域名
*/
hostname: string;
/** Locales for feed */
locales?: Record<string, BaseFeedOptions>;
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc