rss.today 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +702 -0
  3. package/dist/atom1.d.ts +8 -0
  4. package/dist/atom1.d.ts.map +1 -0
  5. package/dist/atom1.js +195 -0
  6. package/dist/atom1.js.map +1 -0
  7. package/dist/config/index.d.ts +2 -0
  8. package/dist/config/index.d.ts.map +1 -0
  9. package/dist/config/index.js +2 -0
  10. package/dist/config/index.js.map +1 -0
  11. package/dist/feed.d.ts +54 -0
  12. package/dist/feed.d.ts.map +1 -0
  13. package/dist/feed.js +58 -0
  14. package/dist/feed.js.map +1 -0
  15. package/dist/index.d.ts +12 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +7 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/json.d.ts +8 -0
  20. package/dist/json.d.ts.map +1 -0
  21. package/dist/json.js +97 -0
  22. package/dist/json.js.map +1 -0
  23. package/dist/parser/fields.d.ts +12 -0
  24. package/dist/parser/fields.d.ts.map +1 -0
  25. package/dist/parser/fields.js +72 -0
  26. package/dist/parser/fields.js.map +1 -0
  27. package/dist/parser/parser.d.ts +93 -0
  28. package/dist/parser/parser.d.ts.map +1 -0
  29. package/dist/parser/parser.js +411 -0
  30. package/dist/parser/parser.js.map +1 -0
  31. package/dist/parser/utils.d.ts +9 -0
  32. package/dist/parser/utils.d.ts.map +1 -0
  33. package/dist/parser/utils.js +81 -0
  34. package/dist/parser/utils.js.map +1 -0
  35. package/dist/parser.d.ts +106 -0
  36. package/dist/parser.d.ts.map +1 -0
  37. package/dist/parser.js +458 -0
  38. package/dist/parser.js.map +1 -0
  39. package/dist/rss0_9.d.ts +4 -0
  40. package/dist/rss0_9.d.ts.map +1 -0
  41. package/dist/rss0_9.js +77 -0
  42. package/dist/rss0_9.js.map +1 -0
  43. package/dist/rss1.d.ts +4 -0
  44. package/dist/rss1.d.ts.map +1 -0
  45. package/dist/rss1.js +92 -0
  46. package/dist/rss1.js.map +1 -0
  47. package/dist/rss2.d.ts +7 -0
  48. package/dist/rss2.d.ts.map +1 -0
  49. package/dist/rss2.js +267 -0
  50. package/dist/rss2.js.map +1 -0
  51. package/dist/test/feed-utils.test.d.ts +2 -0
  52. package/dist/test/feed-utils.test.d.ts.map +1 -0
  53. package/dist/test/feed-utils.test.js +279 -0
  54. package/dist/test/feed-utils.test.js.map +1 -0
  55. package/dist/test/feed.test.d.ts +2 -0
  56. package/dist/test/feed.test.d.ts.map +1 -0
  57. package/dist/test/feed.test.js +190 -0
  58. package/dist/test/feed.test.js.map +1 -0
  59. package/dist/test/opml.test.d.ts +2 -0
  60. package/dist/test/opml.test.d.ts.map +1 -0
  61. package/dist/test/opml.test.js +135 -0
  62. package/dist/test/opml.test.js.map +1 -0
  63. package/dist/test/parser-test.cjs +11 -0
  64. package/dist/test/parser-test.cjs.map +1 -0
  65. package/dist/test/parser-test.d.cts +2 -0
  66. package/dist/test/parser-test.d.cts.map +1 -0
  67. package/dist/test/parser-test01.d.ts +2 -0
  68. package/dist/test/parser-test01.d.ts.map +1 -0
  69. package/dist/test/parser-test01.js +19 -0
  70. package/dist/test/parser-test01.js.map +1 -0
  71. package/dist/test/parser.test.d.ts +2 -0
  72. package/dist/test/parser.test.d.ts.map +1 -0
  73. package/dist/test/parser.test.js +244 -0
  74. package/dist/test/parser.test.js.map +1 -0
  75. package/dist/test/test-01.d.ts +2 -0
  76. package/dist/test/test-01.d.ts.map +1 -0
  77. package/dist/test/test-01.js +7 -0
  78. package/dist/test/test-01.js.map +1 -0
  79. package/dist/test/test-xml2js.d.ts +2 -0
  80. package/dist/test/test-xml2js.d.ts.map +1 -0
  81. package/dist/test/test-xml2js.js +43 -0
  82. package/dist/test/test-xml2js.js.map +1 -0
  83. package/dist/test/test.d.ts +2 -0
  84. package/dist/test/test.d.ts.map +1 -0
  85. package/dist/test/test.js +3 -0
  86. package/dist/test/test.js.map +1 -0
  87. package/dist/test/utilities.test.d.ts +2 -0
  88. package/dist/test/utilities.test.d.ts.map +1 -0
  89. package/dist/test/utilities.test.js +258 -0
  90. package/dist/test/utilities.test.js.map +1 -0
  91. package/dist/types/atom-types.d.ts +100 -0
  92. package/dist/types/atom-types.d.ts.map +1 -0
  93. package/dist/types/atom-types.js +2 -0
  94. package/dist/types/atom-types.js.map +1 -0
  95. package/dist/types/index.d.ts +63 -0
  96. package/dist/types/index.d.ts.map +1 -0
  97. package/dist/types/index.js +2 -0
  98. package/dist/types/index.js.map +1 -0
  99. package/dist/types/rss-types.d.ts +504 -0
  100. package/dist/types/rss-types.d.ts.map +1 -0
  101. package/dist/types/rss-types.js +2 -0
  102. package/dist/types/rss-types.js.map +1 -0
  103. package/dist/uitls/format-check.d.ts +7 -0
  104. package/dist/uitls/format-check.d.ts.map +1 -0
  105. package/dist/uitls/format-check.js +28 -0
  106. package/dist/uitls/format-check.js.map +1 -0
  107. package/dist/uitls/util.d.ts +9 -0
  108. package/dist/uitls/util.d.ts.map +1 -0
  109. package/dist/uitls/util.js +81 -0
  110. package/dist/uitls/util.js.map +1 -0
  111. package/dist/util/converter.d.ts +5 -0
  112. package/dist/util/converter.d.ts.map +1 -0
  113. package/dist/util/converter.js +97 -0
  114. package/dist/util/converter.js.map +1 -0
  115. package/dist/util/feed-utils.d.ts +19 -0
  116. package/dist/util/feed-utils.d.ts.map +1 -0
  117. package/dist/util/feed-utils.js +157 -0
  118. package/dist/util/feed-utils.js.map +1 -0
  119. package/dist/util/opml.d.ts +29 -0
  120. package/dist/util/opml.d.ts.map +1 -0
  121. package/dist/util/opml.js +129 -0
  122. package/dist/util/opml.js.map +1 -0
  123. package/dist/util/validator.d.ts +10 -0
  124. package/dist/util/validator.d.ts.map +1 -0
  125. package/dist/util/validator.js +143 -0
  126. package/dist/util/validator.js.map +1 -0
  127. package/dist/util.d.ts +2 -0
  128. package/dist/util.d.ts.map +1 -0
  129. package/dist/util.js +7 -0
  130. package/dist/util.js.map +1 -0
  131. package/package.json +54 -0
@@ -0,0 +1,279 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mergeFeeds, diffFeeds, filterFeed, filterByCategory, filterByAuthor, filterByDateRange, sortFeed, sortByDate, sortByTitle, limitFeed, deduplicateFeed } from '../util/feed-utils';
3
+ describe('Feed Utilities', () => {
4
+ describe('mergeFeeds', () => {
5
+ it('should merge multiple feeds', () => {
6
+ const feed1 = {
7
+ title: 'Feed 1',
8
+ items: [
9
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-01' },
10
+ { title: 'Item 2', link: 'https://example.com/2', pubDate: '2024-01-02' }
11
+ ]
12
+ };
13
+ const feed2 = {
14
+ title: 'Feed 2',
15
+ items: [
16
+ { title: 'Item 3', link: 'https://example.com/3', pubDate: '2024-01-03' },
17
+ { title: 'Item 4', link: 'https://example.com/4', pubDate: '2024-01-04' }
18
+ ]
19
+ };
20
+ const merged = mergeFeeds([feed1, feed2]);
21
+ expect(merged.items).toHaveLength(4);
22
+ expect(merged.title).toContain('Merged');
23
+ });
24
+ it('should remove duplicates when merging', () => {
25
+ const feed1 = {
26
+ title: 'Feed 1',
27
+ items: [
28
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-01' }
29
+ ]
30
+ };
31
+ const feed2 = {
32
+ title: 'Feed 2',
33
+ items: [
34
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-01' }
35
+ ]
36
+ };
37
+ const merged = mergeFeeds([feed1, feed2]);
38
+ expect(merged.items).toHaveLength(1);
39
+ });
40
+ it('should throw error for zero feeds', () => {
41
+ expect(() => mergeFeeds([])).toThrow('Cannot merge zero feeds');
42
+ });
43
+ });
44
+ describe('diffFeeds', () => {
45
+ it('should detect added items', () => {
46
+ const oldFeed = {
47
+ title: 'Feed',
48
+ items: [
49
+ { title: 'Item 1', link: 'https://example.com/1' }
50
+ ]
51
+ };
52
+ const newFeed = {
53
+ title: 'Feed',
54
+ items: [
55
+ { title: 'Item 1', link: 'https://example.com/1' },
56
+ { title: 'Item 2', link: 'https://example.com/2' }
57
+ ]
58
+ };
59
+ const diff = diffFeeds(oldFeed, newFeed);
60
+ expect(diff.added).toHaveLength(1);
61
+ expect(diff.added[0].title).toBe('Item 2');
62
+ expect(diff.removed).toHaveLength(0);
63
+ expect(diff.modified).toHaveLength(0);
64
+ expect(diff.unchanged).toHaveLength(1);
65
+ });
66
+ it('should detect removed items', () => {
67
+ const oldFeed = {
68
+ title: 'Feed',
69
+ items: [
70
+ { title: 'Item 1', link: 'https://example.com/1' },
71
+ { title: 'Item 2', link: 'https://example.com/2' }
72
+ ]
73
+ };
74
+ const newFeed = {
75
+ title: 'Feed',
76
+ items: [
77
+ { title: 'Item 1', link: 'https://example.com/1' }
78
+ ]
79
+ };
80
+ const diff = diffFeeds(oldFeed, newFeed);
81
+ expect(diff.added).toHaveLength(0);
82
+ expect(diff.removed).toHaveLength(1);
83
+ expect(diff.removed[0].title).toBe('Item 2');
84
+ expect(diff.modified).toHaveLength(0);
85
+ expect(diff.unchanged).toHaveLength(1);
86
+ });
87
+ it('should detect modified items', () => {
88
+ const oldFeed = {
89
+ title: 'Feed',
90
+ items: [
91
+ { title: 'Item 1', link: 'https://example.com/1', description: 'Old description' }
92
+ ]
93
+ };
94
+ const newFeed = {
95
+ title: 'Feed',
96
+ items: [
97
+ { title: 'Item 1', link: 'https://example.com/1', description: 'New description' }
98
+ ]
99
+ };
100
+ const diff = diffFeeds(oldFeed, newFeed);
101
+ expect(diff.added).toHaveLength(0);
102
+ expect(diff.removed).toHaveLength(0);
103
+ expect(diff.modified).toHaveLength(1);
104
+ expect(diff.modified[0].description).toBe('New description');
105
+ });
106
+ });
107
+ describe('filterFeed', () => {
108
+ it('should filter items by predicate', () => {
109
+ const feed = {
110
+ title: 'Feed',
111
+ items: [
112
+ { title: 'Item 1', link: 'https://example.com/1' },
113
+ { title: 'Item 2', link: 'https://example.com/2' },
114
+ { title: 'Item 3', link: 'https://example.com/3' }
115
+ ]
116
+ };
117
+ const filtered = filterFeed(feed, (item, index) => index % 2 === 0);
118
+ expect(filtered.items).toHaveLength(2);
119
+ expect(filtered.items[0].title).toBe('Item 1');
120
+ expect(filtered.items[1].title).toBe('Item 3');
121
+ });
122
+ });
123
+ describe('filterByCategory', () => {
124
+ it('should filter items by category', () => {
125
+ const feed = {
126
+ title: 'Feed',
127
+ items: [
128
+ { title: 'Item 1', link: 'https://example.com/1', categories: [{ name: 'Tech' }] },
129
+ { title: 'Item 2', link: 'https://example.com/2', categories: [{ name: 'News' }] },
130
+ { title: 'Item 3', link: 'https://example.com/3', categories: [{ name: 'Tech' }] }
131
+ ]
132
+ };
133
+ const filtered = filterByCategory(feed, 'Tech');
134
+ expect(filtered.items).toHaveLength(2);
135
+ });
136
+ });
137
+ describe('filterByAuthor', () => {
138
+ it('should filter items by author', () => {
139
+ const feed = {
140
+ title: 'Feed',
141
+ items: [
142
+ { title: 'Item 1', link: 'https://example.com/1', author: 'John' },
143
+ { title: 'Item 2', link: 'https://example.com/2', author: 'Jane' },
144
+ { title: 'Item 3', link: 'https://example.com/3', author: 'John' }
145
+ ]
146
+ };
147
+ const filtered = filterByAuthor(feed, 'John');
148
+ expect(filtered.items).toHaveLength(2);
149
+ });
150
+ });
151
+ describe('filterByDateRange', () => {
152
+ it('should filter items by date range', () => {
153
+ const feed = {
154
+ title: 'Feed',
155
+ items: [
156
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-01' },
157
+ { title: 'Item 2', link: 'https://example.com/2', pubDate: '2024-01-15' },
158
+ { title: 'Item 3', link: 'https://example.com/3', pubDate: '2024-02-01' }
159
+ ]
160
+ };
161
+ const filtered = filterByDateRange(feed, new Date('2024-01-10'), new Date('2024-01-20'));
162
+ expect(filtered.items).toHaveLength(1);
163
+ expect(filtered.items[0].title).toBe('Item 2');
164
+ });
165
+ });
166
+ describe('sortFeed', () => {
167
+ it('should sort items by comparator', () => {
168
+ const feed = {
169
+ title: 'Feed',
170
+ items: [
171
+ { title: 'Zebra', link: 'https://example.com/1' },
172
+ { title: 'Apple', link: 'https://example.com/2' },
173
+ { title: 'Banana', link: 'https://example.com/3' }
174
+ ]
175
+ };
176
+ const sorted = sortFeed(feed, (a, b) => {
177
+ const titleA = a.title || "";
178
+ const titleB = b.title || "";
179
+ return titleA.localeCompare(titleB);
180
+ });
181
+ expect(sorted.items[0].title).toBe('Apple');
182
+ expect(sorted.items[1].title).toBe('Banana');
183
+ expect(sorted.items[2].title).toBe('Zebra');
184
+ });
185
+ });
186
+ describe('sortByDate', () => {
187
+ it('should sort items by date descending', () => {
188
+ const feed = {
189
+ title: 'Feed',
190
+ items: [
191
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-03' },
192
+ { title: 'Item 2', link: 'https://example.com/2', pubDate: '2024-01-01' },
193
+ { title: 'Item 3', link: 'https://example.com/3', pubDate: '2024-01-02' }
194
+ ]
195
+ };
196
+ const sorted = sortByDate(feed, 'desc');
197
+ expect(sorted.items[0].pubDate).toBe('2024-01-03');
198
+ expect(sorted.items[1].pubDate).toBe('2024-01-02');
199
+ expect(sorted.items[2].pubDate).toBe('2024-01-01');
200
+ });
201
+ it('should sort items by date ascending', () => {
202
+ const feed = {
203
+ title: 'Feed',
204
+ items: [
205
+ { title: 'Item 1', link: 'https://example.com/1', pubDate: '2024-01-03' },
206
+ { title: 'Item 2', link: 'https://example.com/2', pubDate: '2024-01-01' },
207
+ { title: 'Item 3', link: 'https://example.com/3', pubDate: '2024-01-02' }
208
+ ]
209
+ };
210
+ const sorted = sortByDate(feed, 'asc');
211
+ expect(sorted.items[0].pubDate).toBe('2024-01-01');
212
+ expect(sorted.items[1].pubDate).toBe('2024-01-02');
213
+ expect(sorted.items[2].pubDate).toBe('2024-01-03');
214
+ });
215
+ });
216
+ describe('sortByTitle', () => {
217
+ it('should sort items by title ascending', () => {
218
+ const feed = {
219
+ title: 'Feed',
220
+ items: [
221
+ { title: 'Zebra', link: 'https://example.com/1' },
222
+ { title: 'Apple', link: 'https://example.com/2' },
223
+ { title: 'Banana', link: 'https://example.com/3' }
224
+ ]
225
+ };
226
+ const sorted = sortByTitle(feed, 'asc');
227
+ expect(sorted.items[0].title).toBe('Apple');
228
+ expect(sorted.items[1].title).toBe('Banana');
229
+ expect(sorted.items[2].title).toBe('Zebra');
230
+ });
231
+ it('should sort items by title descending', () => {
232
+ const feed = {
233
+ title: 'Feed',
234
+ items: [
235
+ { title: 'Zebra', link: 'https://example.com/1' },
236
+ { title: 'Apple', link: 'https://example.com/2' },
237
+ { title: 'Banana', link: 'https://example.com/3' }
238
+ ]
239
+ };
240
+ const sorted = sortByTitle(feed, 'desc');
241
+ expect(sorted.items[0].title).toBe('Zebra');
242
+ expect(sorted.items[1].title).toBe('Banana');
243
+ expect(sorted.items[2].title).toBe('Apple');
244
+ });
245
+ });
246
+ describe('limitFeed', () => {
247
+ it('should limit feed items', () => {
248
+ const feed = {
249
+ title: 'Feed',
250
+ items: [
251
+ { title: 'Item 1', link: 'https://example.com/1' },
252
+ { title: 'Item 2', link: 'https://example.com/2' },
253
+ { title: 'Item 3', link: 'https://example.com/3' },
254
+ { title: 'Item 4', link: 'https://example.com/4' },
255
+ { title: 'Item 5', link: 'https://example.com/5' }
256
+ ]
257
+ };
258
+ const limited = limitFeed(feed, 3);
259
+ expect(limited.items).toHaveLength(3);
260
+ });
261
+ });
262
+ describe('deduplicateFeed', () => {
263
+ it('should remove duplicate items', () => {
264
+ const feed = {
265
+ title: 'Feed',
266
+ items: [
267
+ { title: 'Item 1', link: 'https://example.com/1', guid: '1' },
268
+ { title: 'Item 2', link: 'https://example.com/2', guid: '2' },
269
+ { title: 'Item 1', link: 'https://example.com/1', guid: '1' },
270
+ { title: 'Item 3', link: 'https://example.com/3', guid: '3' }
271
+ ]
272
+ };
273
+ const deduplicated = deduplicateFeed(feed);
274
+ expect(deduplicated.items).toHaveLength(3);
275
+ expect(deduplicated.items.map(i => i.title)).toEqual(['Item 1', 'Item 2', 'Item 3']);
276
+ });
277
+ });
278
+ });
279
+ //# sourceMappingURL=feed-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed-utils.test.js","sourceRoot":"","sources":["../../src/test/feed-utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=feed.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.test.d.ts","sourceRoot":"","sources":["../../src/test/feed.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,190 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { Feed } from '../feed.js';
3
+ describe('Feed', () => {
4
+ let feed;
5
+ beforeEach(() => {
6
+ feed = new Feed({
7
+ title: 'Test Feed',
8
+ description: 'A test feed',
9
+ link: 'https://example.com',
10
+ id: 'https://example.com/feed',
11
+ language: 'en',
12
+ copyright: 'ISC',
13
+ });
14
+ });
15
+ describe('constructor', () => {
16
+ it('should create a feed with options', () => {
17
+ expect(feed.options.title).toBe('Test Feed');
18
+ expect(feed.options.description).toBe('A test feed');
19
+ expect(feed.options.link).toBe('https://example.com');
20
+ });
21
+ it('should initialize empty arrays', () => {
22
+ expect(feed.items).toEqual([]);
23
+ expect(feed.categories).toEqual([]);
24
+ expect(feed.contributors).toEqual([]);
25
+ expect(feed.extensions).toEqual([]);
26
+ });
27
+ });
28
+ describe('addItem', () => {
29
+ it('should add an item to the feed', () => {
30
+ const item = {
31
+ title: 'Test Item',
32
+ link: 'https://example.com/item',
33
+ description: 'Test description',
34
+ date: new Date(),
35
+ };
36
+ feed.addItem(item);
37
+ expect(feed.items).toHaveLength(1);
38
+ expect(feed.items[0]).toEqual(item);
39
+ });
40
+ it('should add multiple items', () => {
41
+ feed.addItem({ title: 'Item 1', link: 'https://example.com/1', date: new Date() });
42
+ feed.addItem({ title: 'Item 2', link: 'https://example.com/2', date: new Date() });
43
+ feed.addItem({ title: 'Item 3', link: 'https://example.com/3', date: new Date() });
44
+ expect(feed.items).toHaveLength(3);
45
+ });
46
+ });
47
+ describe('addCategory', () => {
48
+ it('should add a category to the feed', () => {
49
+ feed.addCategory('technology');
50
+ expect(feed.categories).toHaveLength(1);
51
+ expect(feed.categories[0]).toBe('technology');
52
+ });
53
+ it('should add multiple categories', () => {
54
+ feed.addCategory('technology');
55
+ feed.addCategory('programming');
56
+ feed.addCategory('javascript');
57
+ expect(feed.categories).toHaveLength(3);
58
+ expect(feed.categories).toEqual(['technology', 'programming', 'javascript']);
59
+ });
60
+ });
61
+ describe('addContributor', () => {
62
+ it('should add a contributor to the feed', () => {
63
+ const author = {
64
+ name: 'John Doe',
65
+ email: 'john@example.com',
66
+ };
67
+ feed.addContributor(author);
68
+ expect(feed.contributors).toHaveLength(1);
69
+ expect(feed.contributors[0]).toEqual(author);
70
+ });
71
+ });
72
+ describe('addExtension', () => {
73
+ it('should add an extension to the feed', () => {
74
+ const extension = {
75
+ name: 'itunes',
76
+ objects: { author: 'Podcast Author' },
77
+ };
78
+ feed.addExtension(extension);
79
+ expect(feed.extensions).toHaveLength(1);
80
+ expect(feed.extensions[0]).toEqual(extension);
81
+ });
82
+ });
83
+ describe('rss2', () => {
84
+ it('should generate RSS 2.0 feed', () => {
85
+ feed.addItem({
86
+ title: 'Test Item',
87
+ link: 'https://example.com/item',
88
+ description: 'Test description',
89
+ date: new Date('2024-01-01'),
90
+ });
91
+ const rss = feed.rss2();
92
+ expect(rss).toMatch(/<\?xml version="1\.0" encoding="(UTF-8|utf-8)"\?>/);
93
+ expect(rss).toContain('<rss version="2.0"');
94
+ expect(rss).toContain('<title>Test Feed</title>');
95
+ expect(rss).toContain('<description>A test feed</description>');
96
+ expect(rss).toContain('Test Item');
97
+ });
98
+ });
99
+ describe('atom1', () => {
100
+ it('should generate Atom 1.0 feed', () => {
101
+ feed.addItem({
102
+ title: 'Test Item',
103
+ link: 'https://example.com/item',
104
+ description: 'Test description',
105
+ date: new Date('2024-01-01'),
106
+ });
107
+ const atom = feed.atom1();
108
+ expect(atom).toMatch(/<\?xml version="1\.0" encoding="(UTF-8|utf-8)"\?>/);
109
+ expect(atom).toContain('<feed xmlns="http://www.w3.org/2005/Atom"');
110
+ expect(atom).toContain('<title>Test Feed</title>');
111
+ expect(atom).toContain('Test Item');
112
+ });
113
+ });
114
+ describe('json1', () => {
115
+ it('should generate JSON 1.0 feed', () => {
116
+ feed.addItem({
117
+ title: 'Test Item',
118
+ link: 'https://example.com/item',
119
+ description: 'Test description',
120
+ date: new Date('2024-01-01'),
121
+ });
122
+ const json = feed.json1();
123
+ const parsed = JSON.parse(json);
124
+ expect(parsed.version).toBe('https://jsonfeed.org/version/1');
125
+ expect(parsed.title).toBe('Test Feed');
126
+ expect(parsed.items).toHaveLength(1);
127
+ expect(parsed.items[0].title).toBe('Test Item');
128
+ });
129
+ });
130
+ describe('complete feed generation', () => {
131
+ it('should generate a complete feed with all features', () => {
132
+ // Add categories
133
+ feed.addCategory('technology');
134
+ feed.addCategory('programming');
135
+ // Add contributors
136
+ feed.addContributor({
137
+ name: 'Jane Doe',
138
+ email: 'jane@example.com',
139
+ link: 'https://example.com/jane',
140
+ });
141
+ // Add items with various properties
142
+ feed.addItem({
143
+ title: 'First Post',
144
+ link: 'https://example.com/first',
145
+ description: 'First post content',
146
+ content: 'Full content of the first post',
147
+ author: [{ name: 'Jane Doe' }],
148
+ date: new Date('2024-01-01T00:00:00Z'),
149
+ });
150
+ feed.addItem({
151
+ title: 'Second Post',
152
+ link: 'https://example.com/second',
153
+ description: 'Second post content',
154
+ date: new Date('2024-01-02T00:00:00Z'),
155
+ });
156
+ // Test RSS 2.0 output
157
+ const rss = feed.rss2();
158
+ expect(rss).toContain('First Post');
159
+ expect(rss).toContain('Second Post');
160
+ // Test Atom 1.0 output
161
+ const atom = feed.atom1();
162
+ expect(atom).toContain('First Post');
163
+ expect(atom).toContain('Second Post');
164
+ // Test JSON 1.0 output
165
+ const json = feed.json1();
166
+ const parsed = JSON.parse(json);
167
+ expect(parsed.items).toHaveLength(2);
168
+ });
169
+ });
170
+ describe('item with enclosures', () => {
171
+ it('should handle items with media enclosures', () => {
172
+ feed.addItem({
173
+ title: 'Podcast Episode',
174
+ link: 'https://example.com/episode',
175
+ description: 'Episode description',
176
+ date: new Date(),
177
+ enclosure: {
178
+ url: 'https://example.com/episode.mp3',
179
+ type: 'audio/mpeg',
180
+ length: 12345678,
181
+ },
182
+ });
183
+ const rss = feed.rss2();
184
+ expect(rss).toContain('<enclosure');
185
+ expect(rss).toContain('url="https://example.com/episode.mp3"');
186
+ expect(rss).toContain('type="audio/mpeg"');
187
+ });
188
+ });
189
+ });
190
+ //# sourceMappingURL=feed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.test.js","sourceRoot":"","sources":["../../src/test/feed.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=opml.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opml.test.d.ts","sourceRoot":"","sources":["../../src/test/opml.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { OPMLParser, OPMLGenerator } from '../util/opml';
3
+ describe('OPML', () => {
4
+ describe('OPMLParser', () => {
5
+ it('should parse a valid OPML document', async () => {
6
+ const opmlXml = `<?xml version="1.0" encoding="UTF-8"?>
7
+ <opml version="1.0">
8
+ <head>
9
+ <title>My Subscriptions</title>
10
+ <dateCreated>2024-01-01T00:00:00Z</dateCreated>
11
+ <ownerName>John Doe</ownerName>
12
+ <ownerEmail>john@example.com</ownerEmail>
13
+ </head>
14
+ <body>
15
+ <outline text="TechCrunch" type="rss" xmlUrl="https://techcrunch.com/feed/" htmlUrl="https://techcrunch.com"/>
16
+ <outline text="BBC News" type="rss" xmlUrl="http://feeds.bbci.co.uk/news/rss.xml" htmlUrl="https://www.bbc.com/news"/>
17
+ </body>
18
+ </opml>`;
19
+ const parser = new OPMLParser();
20
+ const result = await parser.parseOPML(opmlXml);
21
+ expect(result.version).toBe('1.0');
22
+ expect(result.title).toBe('My Subscriptions');
23
+ expect(result.dateCreated).toEqual(new Date('2024-01-01T00:00:00Z'));
24
+ expect(result.ownerName).toBe('John Doe');
25
+ expect(result.ownerEmail).toBe('john@example.com');
26
+ expect(result.outlines).toHaveLength(2);
27
+ });
28
+ it('should parse nested outlines', async () => {
29
+ const opmlXml = `<?xml version="1.0" encoding="UTF-8"?>
30
+ <opml version="1.0">
31
+ <body>
32
+ <outline text="Technology">
33
+ <outline text="TechCrunch" type="rss" xmlUrl="https://techcrunch.com/feed/"/>
34
+ <outline text="Hacker News" type="rss" xmlUrl="https://news.ycombinator.com/rss"/>
35
+ </outline>
36
+ </body>
37
+ </opml>`;
38
+ const parser = new OPMLParser();
39
+ const result = await parser.parseOPML(opmlXml);
40
+ expect(result.outlines).toHaveLength(1);
41
+ expect(result.outlines[0].text).toBe('Technology');
42
+ expect(result.outlines[0].outlines).toHaveLength(2);
43
+ expect(result.outlines[0].outlines[0].text).toBe('TechCrunch');
44
+ });
45
+ it('should parse categories', async () => {
46
+ const opmlXml = `<?xml version="1.0" encoding="UTF-8"?>
47
+ <opml version="1.0">
48
+ <body>
49
+ <outline text="TechCrunch" category="Tech, News" type="rss" xmlUrl="https://techcrunch.com/feed/"/>
50
+ </body>
51
+ </opml>`;
52
+ const parser = new OPMLParser();
53
+ const result = await parser.parseOPML(opmlXml);
54
+ expect(result.outlines[0].category).toEqual(['Tech', 'News']);
55
+ });
56
+ it('should throw error for invalid XML', async () => {
57
+ const invalidXml = 'not xml';
58
+ const parser = new OPMLParser();
59
+ await expect(parser.parseOPML(invalidXml)).rejects.toThrow();
60
+ });
61
+ it('should throw error for missing opml element', async () => {
62
+ const invalidXml = '<?xml version="1.0"?><root></root>';
63
+ const parser = new OPMLParser();
64
+ await expect(parser.parseOPML(invalidXml)).rejects.toThrow('missing root opml element');
65
+ });
66
+ });
67
+ describe('OPMLGenerator', () => {
68
+ it('should generate valid OPML document', () => {
69
+ const opml = {
70
+ version: '1.0',
71
+ title: 'My Subscriptions',
72
+ dateCreated: new Date('2024-01-01T00:00:00Z'),
73
+ ownerName: 'John Doe',
74
+ ownerEmail: 'john@example.com',
75
+ outlines: [
76
+ {
77
+ text: 'TechCrunch',
78
+ type: 'rss',
79
+ xmlUrl: 'https://techcrunch.com/feed/',
80
+ htmlUrl: 'https://techcrunch.com'
81
+ }
82
+ ]
83
+ };
84
+ const generator = new OPMLGenerator();
85
+ const result = generator.generateOPML(opml);
86
+ expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>');
87
+ expect(result).toContain('<opml version="1.0">');
88
+ expect(result).toContain('<title>My Subscriptions</title>');
89
+ expect(result).toContain('<dateCreated>2024-01-01T00:00:00.000Z</dateCreated>');
90
+ expect(result).toContain('<ownerName>John Doe</ownerName>');
91
+ expect(result).toContain('<outline text="TechCrunch"');
92
+ expect(result).toContain('type="rss"');
93
+ expect(result).toContain('xmlUrl="https://techcrunch.com/feed/"');
94
+ expect(result).toContain('htmlUrl="https://techcrunch.com"');
95
+ });
96
+ it('should generate nested outlines', () => {
97
+ const opml = {
98
+ version: '1.0',
99
+ outlines: [
100
+ {
101
+ text: 'Technology',
102
+ outlines: [
103
+ {
104
+ text: 'TechCrunch',
105
+ type: 'rss',
106
+ xmlUrl: 'https://techcrunch.com/feed/'
107
+ }
108
+ ]
109
+ }
110
+ ]
111
+ };
112
+ const generator = new OPMLGenerator();
113
+ const result = generator.generateOPML(opml);
114
+ expect(result).toContain('<outline text="Technology">');
115
+ expect(result).toContain('<outline text="TechCrunch"');
116
+ expect(result).toContain('</outline>');
117
+ });
118
+ it('should escape special characters', () => {
119
+ const opml = {
120
+ version: '1.0',
121
+ outlines: [
122
+ {
123
+ text: 'Tech & "News"',
124
+ type: 'rss',
125
+ xmlUrl: 'https://example.com/feed'
126
+ }
127
+ ]
128
+ };
129
+ const generator = new OPMLGenerator();
130
+ const result = generator.generateOPML(opml);
131
+ expect(result).toContain('Tech &amp; &quot;News&quot;');
132
+ });
133
+ });
134
+ });
135
+ //# sourceMappingURL=opml.test.js.map