Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: make RSS canonicalUrl required #3301

Merged
merged 4 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions packages/astro-rss/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import rss from '@astrojs/rss';
export const get = () => rss({
title: 'Buzz’s Blog',
description: 'A humble Astronaut’s guide to the stars',
// pull in the "site" from your project's astro.config
canonicalUrl: import.meta.env.SITE,
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
items: import.meta.glob('./blog/**/*.md'),
});
```
Expand All @@ -44,6 +46,8 @@ rss({
title: 'Buzz’s Blog',
// `<description>` field in output xml
description: 'A humble Astronaut’s guide to the stars',
// provide a base URL for RSS <item> links
canonicalUrl: import.meta.env.SITE,
bholmesdev marked this conversation as resolved.
Show resolved Hide resolved
// list of `<item>`s in output xml
items: import.meta.glob('./**/*.md'),
// (optional) absolute path to XSL stylesheet in your project
Expand All @@ -52,9 +56,6 @@ rss({
customData: '<language>en-us</language>',
// (optional) add arbitrary metadata to opening <rss> tag
xmlns: { h: 'http://www.w3.org/TR/html4/' },
// (optional) provide a canonical URL
// defaults to the "site" configured in your project's astro.config
canonicalUrl: 'https://stargazers.club',
});
```

Expand All @@ -70,6 +71,12 @@ Type: `string (required)`

The `<description>` attribute of your RSS feed's output xml.

### canonicalUrl

Type: `string (required)`

The base URL to use when generating RSS item links. We recommend using `import.meta.env.SITE` to pull in the "site" from your project's astro.config. Still, feel free to use a custom base URL if necessary.

### items

Type: `RSSFeedItem[] | GlobResult (required)`
Expand Down Expand Up @@ -135,11 +142,7 @@ Will inject the following XML:
<rss xmlns:h="http://www.w3.org/TR/html4/"...
```

### canonicalUrl

Type: `string (optional)`

The base URL to use when generating RSS item links. This defaults to the [`site` configured in your project's `astro.config`](https://docs.astro.build/en/reference/configuration-reference/#site). We recommend using `site` instead of `canonicalUrl`, though we provide this option if an override is necessary.
---

For more on building with Astro, [visit the Astro docs][astro-rss].

Expand Down
26 changes: 10 additions & 16 deletions packages/astro-rss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ type RSSOptions = {
title: string;
/** (required) Description of the RSS Feed */
description: string;
/**
* Specify the base URL to use for RSS feed links.
* We recommend "import.meta.env.SITE" to pull in the "site"
* from your project's astro.config.
*/
canonicalUrl: string;
/**
* List of RSS feed items to render. Accepts either:
* a) list of RSSFeedItems
Expand All @@ -22,11 +28,6 @@ type RSSOptions = {
stylesheet?: string | boolean;
/** Specify custom data in opening of file */
customData?: string;
/**
* Specify the base URL to use for RSS feed links.
* Defaults to "site" in your project's astro.config
*/
canonicalUrl?: string;
};

type RSSFeedItem = {
Expand All @@ -43,7 +44,6 @@ type RSSFeedItem = {
};

type GenerateRSSArgs = {
site: string;
rssOptions: RSSOptions;
items: RSSFeedItem[];
};
Expand Down Expand Up @@ -76,27 +76,21 @@ function mapGlobResult(items: GlobResult): Promise<RSSFeedItem[]> {
}

export default async function getRSS(rssOptions: RSSOptions) {
const site = rssOptions.canonicalUrl ?? (import.meta as any).env.SITE;
if (!site) {
throw new Error(
`RSS requires a canonical URL. Either add a "site" to your project's astro.config, or supply the canonicalUrl argument.`
);
}
let { items } = rssOptions;
if (isGlobResult(items)) {
items = await mapGlobResult(items);
}
return {
body: await generateRSS({
site,
rssOptions,
items,
}),
};
}

/** Generate RSS 2.0 feed */
export async function generateRSS({ site, rssOptions, items }: GenerateRSSArgs): Promise<string> {
export async function generateRSS({ rssOptions, items }: GenerateRSSArgs): Promise<string> {
const { canonicalUrl } = rssOptions;
let xml = `<?xml version="1.0" encoding="UTF-8"?>`;
if (typeof rssOptions.stylesheet === 'string') {
xml += `<?xml-stylesheet href="${rssOptions.stylesheet}" type="text/xsl"?>`;
Expand All @@ -115,7 +109,7 @@ export async function generateRSS({ site, rssOptions, items }: GenerateRSSArgs):
// title, description, customData
xml += `<title><![CDATA[${rssOptions.title}]]></title>`;
xml += `<description><![CDATA[${rssOptions.description}]]></description>`;
xml += `<link>${createCanonicalURL(site).href}</link>`;
xml += `<link>${createCanonicalURL(canonicalUrl).href}</link>`;
if (typeof rssOptions.customData === 'string') xml += rssOptions.customData;
// items
for (const result of items) {
Expand All @@ -124,7 +118,7 @@ export async function generateRSS({ site, rssOptions, items }: GenerateRSSArgs):
// If the item's link is already a valid URL, don't mess with it.
const itemLink = isValidURL(result.link)
? result.link
: createCanonicalURL(result.link, site).href;
: createCanonicalURL(result.link, canonicalUrl).href;
xml += `<link>${itemLink}</link>`;
xml += `<guid>${itemLink}</guid>`;
if (result.description) xml += `<description><![CDATA[${result.description}]]></description>`;
Expand Down
10 changes: 0 additions & 10 deletions packages/astro-rss/test/rss.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ const web1FeedItem = {
const validXmlResult = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title><![CDATA[My RSS feed]]></title><description><![CDATA[This sure is a nice RSS feed]]></description><link>https://example.com/</link><item><title><![CDATA[Remember PHP?]]></title><link>https://example.com/php/</link><guid>https://example.com/php/</guid><description><![CDATA[PHP is a general-purpose scripting language geared toward web development. It was originally created by Danish-Canadian programmer Rasmus Lerdorf in 1994.]]></description><pubDate>Tue, 03 May 1994 00:00:00 GMT</pubDate></item><item><title><![CDATA[Web 1.0]]></title><link>https://example.com/web1/</link><guid>https://example.com/web1/</guid><description><![CDATA[Web 1.0 is the term used for the earliest version of the Internet as it emerged from its origins with Defense Advanced Research Projects Agency (DARPA) and became, for the first time, a global network representing the future of digital communications.]]></description><pubDate>Sat, 03 May 1997 00:00:00 GMT</pubDate></item></channel></rss>`;

describe('rss', () => {
it('should fail on missing "site" and/or "canonicalUrl"', () => {
return chai.expect(
rss({
title,
description,
items: [],
})
).to.be.rejected;
});

it('should generate on valid RSSFeedItem array', async () => {
const { body } = await rss({
title,
Expand Down