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;