diff --git a/src/__tests__/rss2.spec.ts b/src/__tests__/rss2.spec.ts index dc520da..f94fe2c 100644 --- a/src/__tests__/rss2.spec.ts +++ b/src/__tests__/rss2.spec.ts @@ -1,6 +1,56 @@ import { Feed } from "../feed"; import { createSampleFeed, published, sampleFeed, updated } from "./setup"; +describe("rss 2.0 isPermaLink override", () => { + it("should specify isPermaLink=true when feed item specifies an id and explicitly sets isPermaLink to true", () => { + const feed = createSampleFeed(); + feed.addItem({ + title: "Hello World", + id: "http://example.org/id-that-is-also-a-real-url", + link: "http://example.org/id-that-is-also-a-real-url", + isPermaLink: true, + date: published, + }); + const actual = feed.rss2(); + expect(actual).toContain('http://example.org/id-that-is-also-a-real-url'); + }); + + it("should specify isPermaLink=false when feed item specifies only a link but explicitly sets isPermaLink to false", () => { + const feed = createSampleFeed(); + feed.addItem({ + title: "Hello World", + link: "http://example.org/link-that-is-not-a-stable-id", + isPermaLink: false, + date: published, + }); + const actual = feed.rss2(); + expect(actual).toContain('http://example.org/link-that-is-not-a-stable-id'); + }); + + it("should still default to isPermaLink=false for a guid when isPermaLink is not set (no regression)", () => { + const feed = createSampleFeed(); + feed.addItem({ + title: "Hello World", + guid: "50e14f43-dd4e-412f-864d-78943ea28d91", + link: "http://example.org/guid", + date: published, + }); + const actual = feed.rss2(); + expect(actual).toContain('50e14f43-dd4e-412f-864d-78943ea28d91'); + }); + + it("should still default to isPermaLink=true for a link-only item when isPermaLink is not set (no regression)", () => { + const feed = createSampleFeed(); + feed.addItem({ + title: "Hello World", + link: "http://example.org/link", + date: published, + }); + const actual = feed.rss2(); + expect(actual).toContain('http://example.org/link'); + }); +}); + describe("rss 2.0", () => { it("should generate a valid feed", () => { const actual = sampleFeed.rss2(); diff --git a/src/rss2.ts b/src/rss2.ts index d527fa9..da585db 100644 --- a/src/rss2.ts +++ b/src/rss2.ts @@ -107,11 +107,14 @@ export default (ins: Feed) => { } if (entry.guid) { - item.guid = { _text: entry.guid, _attributes: { isPermaLink: false } }; + item.guid = { _text: entry.guid, _attributes: { isPermaLink: entry.isPermaLink ?? false } }; } else if (entry.id) { - item.guid = { _text: entry.id, _attributes: { isPermaLink: false } }; + item.guid = { _text: entry.id, _attributes: { isPermaLink: entry.isPermaLink ?? false } }; } else if (entry.link) { - item.guid = { _text: sanitizeUrl(entry.link), _attributes: { isPermaLink: true } }; + item.guid = { + _text: sanitizeUrl(entry.link), + _attributes: { isPermaLink: entry.isPermaLink ?? true }, + }; } if (entry.date) { diff --git a/src/typings/index.ts b/src/typings/index.ts index fd69e05..3f93069 100644 --- a/src/typings/index.ts +++ b/src/typings/index.ts @@ -9,6 +9,16 @@ export interface Item { category?: Category[]; guid?: string; + /** + * Explicitly control the `isPermaLink` attribute on the RSS 2.0 `` element. + * + * If omitted, the existing inference is used: `false` when `guid` or `id` + * is set, `true` when only `link` is set. Pass `true` or `false` here to + * override that inference, e.g. when `id`/`guid` happens to be a real, + * permanent URL (`true`) or when `link` is a permanent URL but `id`/`guid` + * is an opaque, non-URL identifier that should stay `false`. + */ + isPermaLink?: boolean; image?: string | Enclosure; audio?: string | Enclosure;