Skip to content

Commit 8cff621

Browse files
committed
feat: use dc:subject as a feed/item category
This adds `dc:subject` to the list of elements that can be pulled into feed and item categories, for both Atom and RSS. The element is only supposed to have inner text so we've just taken that and used the same value for both the category term and label. Resolves #156.
1 parent 3d75104 commit 8cff621

File tree

11 files changed

+141
-62
lines changed

11 files changed

+141
-62
lines changed

lib/feed/atom.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -275,24 +275,26 @@ class AtomFeed extends Feed {
275275
* Returns the categories the feed belongs to.
276276
*/
277277
get categories() {
278-
return this.element
279-
.findElementsWithName('category')
280-
.map((category) => {
281-
const term = category.getAttribute('term') || null;
282-
const label = category.getAttribute('label') || term;
283-
const url = category.getAttributeAsUrl('scheme') || null;
284-
285-
if (!term) {
286-
return null;
287-
}
278+
const categories = this.element.findElementsWithName('category').map((category) => {
279+
const term = category.getAttribute('term') || null;
280+
const label = category.getAttribute('label') || term;
281+
const url = category.getAttributeAsUrl('scheme') || null;
288282

289-
return {
290-
label,
291-
term,
292-
url
293-
};
294-
})
295-
.filter(isNotNull);
283+
if (!term) {
284+
return null;
285+
}
286+
287+
return {
288+
label,
289+
term,
290+
url
291+
};
292+
});
293+
const subjects = this.element.findElementsWithName('subject').map((subject) => {
294+
const term = subject.textContentNormalized;
295+
return term ? { term, label: term, url: null } : null;
296+
});
297+
return [...categories, ...subjects].filter(isNotNull);
296298
}
297299

298300
/**

lib/feed/item/atom.js

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -232,24 +232,26 @@ class AtomFeedItem extends FeedItem {
232232
* Returns the categories the feed item belongs to.
233233
*/
234234
get categories() {
235-
const itemCategories = this.element
236-
.findElementsWithName('category')
237-
.map((category) => {
238-
const term = category.getAttribute('term') || null;
239-
const label = category.getAttribute('label') || term;
240-
const url = category.getAttributeAsUrl('scheme') || null;
235+
const categories = this.element.findElementsWithName('category').map((category) => {
236+
const term = category.getAttribute('term') || null;
237+
const label = category.getAttribute('label') || term;
238+
const url = category.getAttributeAsUrl('scheme') || null;
241239

242-
if (!term) {
243-
return null;
244-
}
240+
if (!term) {
241+
return null;
242+
}
245243

246-
return {
247-
label,
248-
term,
249-
url
250-
};
251-
})
252-
.filter(isNotNull);
244+
return {
245+
label,
246+
term,
247+
url
248+
};
249+
});
250+
const subjects = this.element.findElementsWithName('subject').map((subject) => {
251+
const term = subject.textContentNormalized;
252+
return term ? { term, label: term, url: null } : null;
253+
});
254+
const itemCategories = [...categories, ...subjects].filter(isNotNull);
253255
return itemCategories.length ? itemCategories : this.feed.categories;
254256
}
255257
}

lib/feed/item/rss.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -223,24 +223,26 @@ class RssFeedItem extends FeedItem {
223223
* Returns the categories the feed item belongs to.
224224
*/
225225
get categories() {
226-
const itemCategories = this.element
227-
.findElementsWithName('category')
228-
.map((category) => {
229-
const term = category.textContentNormalized;
230-
const domain = category.getAttribute('domain') || '';
231-
const url = httpRegExp.test(domain) ? category.getAttributeAsUrl('domain') : null;
232-
233-
if (!term) {
234-
return null;
235-
}
226+
const categories = this.element.findElementsWithName('category').map((category) => {
227+
const term = category.textContentNormalized;
228+
const domain = category.getAttribute('domain') || '';
229+
const url = httpRegExp.test(domain) ? category.getAttributeAsUrl('domain') : null;
236230

237-
return {
238-
label: term,
239-
term,
240-
url
241-
};
242-
})
243-
.filter(isNotNull);
231+
if (!term) {
232+
return null;
233+
}
234+
235+
return {
236+
label: term,
237+
term,
238+
url
239+
};
240+
});
241+
const subjects = this.element.findElementsWithName('subject').map((subject) => {
242+
const term = subject.textContentNormalized;
243+
return term ? { term, label: term, url: null } : null;
244+
});
245+
const itemCategories = [...categories, ...subjects].filter(isNotNull);
244246
return itemCategories.length ? itemCategories : this.feed.categories;
245247
}
246248
}

lib/feed/rss.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,7 @@ class RssFeed extends Feed {
314314
term,
315315
url
316316
};
317-
})
318-
.filter(isNotNull);
317+
});
319318
const itunesCategories = categoryElements
320319
.filter((category) => RssFeed.#isItunesElement(category))
321320
.flatMap((category) => {
@@ -349,9 +348,12 @@ class RssFeed extends Feed {
349348
term: level1Category,
350349
url
351350
};
352-
})
353-
.filter(isNotNull);
354-
return [...categories, ...itunesCategories];
351+
});
352+
const subjects = this.element.findElementsWithName('subject').map((subject) => {
353+
const term = subject.textContentNormalized;
354+
return term ? { term, label: term, url: null } : null;
355+
});
356+
return [...categories, ...itunesCategories, ...subjects].filter(isNotNull);
355357
}
356358

357359
/**

test/integration/snapshots/examples/310dd91912797fd15510990ef493494c.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@
4343
"url": null
4444
}
4545
],
46-
"categories": []
46+
"categories": [
47+
{
48+
"term": "XML",
49+
"label": "XML",
50+
"url": null
51+
}
52+
]
4753
}
4854
]
4955
}

test/integration/snapshots/examples/bafde7eafa7b3c5201afdb7851382ac1.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@
4343
"url": null
4444
}
4545
],
46-
"categories": []
46+
"categories": [
47+
{
48+
"term": "Quotes",
49+
"label": "Quotes",
50+
"url": null
51+
}
52+
]
4753
}
4854
]
4955
}

test/integration/snapshots/examples/d90de12e664705f278555918d8f26bdf.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@
4343
"url": null
4444
}
4545
],
46-
"categories": []
46+
"categories": [
47+
{
48+
"term": "Quotes",
49+
"label": "Quotes",
50+
"url": null
51+
}
52+
]
4753
}
4854
]
4955
}

test/unit/lib/feed/atom.test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ describe('lib/feed/atom', () => {
664664
describe('.categories', () => {
665665
let categories;
666666
let mockCategoryElements;
667+
let mockSubjectElements;
667668

668669
beforeEach(() => {
669670
mockCategoryElements = [
@@ -675,6 +676,10 @@ describe('lib/feed/atom', () => {
675676
td.when(mockRootElement.findElementsWithName('category')).thenReturn(
676677
mockCategoryElements
677678
);
679+
mockSubjectElements = [new MockElement(), new MockElement()];
680+
td.when(mockRootElement.findElementsWithName('subject')).thenReturn(
681+
mockSubjectElements
682+
);
678683

679684
td.when(mockCategoryElements[0].getAttribute('term')).thenReturn(
680685
'mock-category-term'
@@ -694,12 +699,14 @@ describe('lib/feed/atom', () => {
694699
'mock-category-label'
695700
);
696701

702+
mockSubjectElements[0].textContentNormalized = 'mock-subject-text';
703+
697704
categories = feed.categories;
698705
});
699706

700707
it('is set to an array of category objects, ignoring ones that do not have a term', () => {
701708
assert.ok(Array.isArray(categories));
702-
assert.strictEqual(categories.length, 2);
709+
assert.strictEqual(categories.length, 3);
703710
assert.deepEqual(categories[0], {
704711
term: 'mock-category-term',
705712
label: 'mock-category-label',
@@ -710,6 +717,11 @@ describe('lib/feed/atom', () => {
710717
label: 'mock-category-term',
711718
url: null
712719
});
720+
assert.deepEqual(categories[2], {
721+
term: 'mock-subject-text',
722+
label: 'mock-subject-text',
723+
url: null
724+
});
713725
});
714726
});
715727

test/unit/lib/feed/item/atom.test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@ describe('lib/feed/item/atom', () => {
726726
describe('.categories', () => {
727727
let categories;
728728
let mockCategoryElements;
729+
let mockSubjectElements;
729730

730731
beforeEach(() => {
731732
mockCategoryElements = [
@@ -738,6 +739,11 @@ describe('lib/feed/item/atom', () => {
738739
mockCategoryElements
739740
);
740741

742+
mockSubjectElements = [new MockElement(), new MockElement()];
743+
td.when(mockItemElement.findElementsWithName('subject')).thenReturn(
744+
mockSubjectElements
745+
);
746+
741747
td.when(mockCategoryElements[0].getAttribute('term')).thenReturn(
742748
'mock-category-term'
743749
);
@@ -756,12 +762,14 @@ describe('lib/feed/item/atom', () => {
756762
'mock-category-label'
757763
);
758764

765+
mockSubjectElements[0].textContentNormalized = 'mock-subject-text';
766+
759767
categories = feedItem.categories;
760768
});
761769

762770
it('is set to an array of category objects, ignoring ones that do not have a term', () => {
763771
assert.ok(Array.isArray(categories));
764-
assert.strictEqual(categories.length, 2);
772+
assert.strictEqual(categories.length, 3);
765773
assert.deepEqual(categories[0], {
766774
term: 'mock-category-term',
767775
label: 'mock-category-label',
@@ -772,11 +780,17 @@ describe('lib/feed/item/atom', () => {
772780
label: 'mock-category-term',
773781
url: null
774782
});
783+
assert.deepEqual(categories[2], {
784+
term: 'mock-subject-text',
785+
label: 'mock-subject-text',
786+
url: null
787+
});
775788
});
776789

777790
describe('when there are no category elements', () => {
778791
beforeEach(() => {
779792
td.when(mockItemElement.findElementsWithName('category')).thenReturn([]);
793+
td.when(mockItemElement.findElementsWithName('subject')).thenReturn([]);
780794
categories = feedItem.categories;
781795
});
782796

test/unit/lib/feed/item/rss.test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ describe('lib/feed/item/rss', () => {
676676
describe('.categories', () => {
677677
let categories;
678678
let mockCategoryElements;
679+
let mockSubjectElements;
679680

680681
beforeEach(() => {
681682
mockCategoryElements = [
@@ -690,6 +691,11 @@ describe('lib/feed/item/rss', () => {
690691
mockCategoryElements
691692
);
692693

694+
mockSubjectElements = [new MockElement(), new MockElement()];
695+
td.when(mockItemElement.findElementsWithName('subject')).thenReturn(
696+
mockSubjectElements
697+
);
698+
693699
mockCategoryElements[0].textContentNormalized = 'mock-category-text';
694700
td.when(mockCategoryElements[0].getAttribute('domain')).thenReturn(
695701
'https://mock-category-domain'
@@ -720,12 +726,14 @@ describe('lib/feed/item/rss', () => {
720726
'mock-category-domain-as-url'
721727
);
722728

729+
mockSubjectElements[0].textContentNormalized = 'mock-subject-text';
730+
723731
categories = feedItem.categories;
724732
});
725733

726734
it('is set to an array of category objects, ignoring ones that do not have text', () => {
727735
assert.ok(Array.isArray(categories));
728-
assert.strictEqual(categories.length, 4);
736+
assert.strictEqual(categories.length, 5);
729737
assert.deepEqual(categories, [
730738
{
731739
term: 'mock-category-text',
@@ -746,13 +754,19 @@ describe('lib/feed/item/rss', () => {
746754
term: 'mock-category-text',
747755
label: 'mock-category-text',
748756
url: null
757+
},
758+
{
759+
term: 'mock-subject-text',
760+
label: 'mock-subject-text',
761+
url: null
749762
}
750763
]);
751764
});
752765

753766
describe('when there are no category elements', () => {
754767
beforeEach(() => {
755768
td.when(mockItemElement.findElementsWithName('category')).thenReturn([]);
769+
td.when(mockItemElement.findElementsWithName('subject')).thenReturn([]);
756770
categories = feedItem.categories;
757771
});
758772

0 commit comments

Comments
 (0)