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 categories under Feed an optional type #56

Merged
merged 3 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"https://deno.land/": true
},
"editor.renderWhitespace": "all",
"discord.enabled": true
"discord.enabled": true,
"editor.defaultFormatter": "denoland.vscode-deno"
}
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,46 +99,57 @@ const mediaContent = entries[0][MediaRss.Content];
## Development

### Local sample parsing

Using Denon

```shell
denon start
```

Using Deno

```shell
deno run --allow-read dev.ts atom
```

### Testing

Using Denon

```shell
denon test
```

Using Deno

```shell
deno test --allow-read
```

### Benchmark

Using Denon

```shell
denon benchmark
```

Using Deno

```shell
deno bench --allow-read bench.ts
```

### Memory footprint test

Using Denon

```shell
denon memory
```

Using Deno

```shell
deno run --allow-read dev_memory_usage.ts
```

18 changes: 9 additions & 9 deletions bench.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { parseFeed } from "./mod.ts";

Deno.bench('Parse RSS1', async (b) => {
let source = await Deno.readTextFile(`./samples/rss1.xml`);
Deno.bench("Parse RSS1", async (b) => {
let source = await Deno.readTextFile(`./samples/rss1.xml`);
b.start();
await parseFeed(source);
b.end();
source = '';
source = "";
});

Deno.bench('Parse RSS2', async (b) => {
let source = await Deno.readTextFile(`./samples/rss2.xml`);
Deno.bench("Parse RSS2", async (b) => {
let source = await Deno.readTextFile(`./samples/rss2.xml`);
b.start();
await parseFeed(source);
b.end();
source = '';
source = "";
});

Deno.bench('Parse ATOM', async (b) => {
let source = await Deno.readTextFile(`./samples/atom.xml`);
Deno.bench("Parse ATOM", async (b) => {
let source = await Deno.readTextFile(`./samples/atom.xml`);
b.start();
await parseFeed(source);
b.end();
source = '';
source = "";
});
2 changes: 1 addition & 1 deletion dev_fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { parseFeed } from "./mod.ts";
"http://rss.slashdot.org/Slashdot/slashdotMain",
"https://www.fz.se/feeds/forum",
"https://developers.googleblog.com/feeds/posts/default",
"https://medium.com/feed/invironment/tagged/food"
"https://medium.com/feed/invironment/tagged/food",
].forEach(async (feedUrl, index, arr) => {
const response = await fetch(feedUrl);
const xml = await response.text();
Expand Down
17 changes: 13 additions & 4 deletions dev_memory_usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ for (let index = 0; index < iterations; index++) {
if (index % snapshotPos === 0) {
const pos = index / snapshotPos;
if (pos < snapshotCount) {
heapUsageArr[pos] = (Deno.memoryUsage().heapUsed - initialDenoProcessAndV8MemoryUsage.heapUsed) / 1024 / 1024;
heapTopArr[pos] = (Deno.memoryUsage().heapTotal - initialDenoProcessAndV8MemoryUsage.heapTotal) / 1024 / 1024;
rssArr[pos] = (Deno.memoryUsage().rss - initialDenoProcessAndV8MemoryUsage.rss) / 1024 / 1024;
heapUsageArr[pos] = (Deno.memoryUsage().heapUsed -
initialDenoProcessAndV8MemoryUsage.heapUsed) / 1024 / 1024;
heapTopArr[pos] = (Deno.memoryUsage().heapTotal -
initialDenoProcessAndV8MemoryUsage.heapTotal) / 1024 / 1024;
rssArr[pos] =
(Deno.memoryUsage().rss - initialDenoProcessAndV8MemoryUsage.rss) /
1024 / 1024;
}
}
}

console.log(`\nMemory usage (Heap: Blue, Heap Top: Green, RSS: Red)`);
console.log(plot([heapUsageArr, heapTopArr, rssArr], { colors: ["blue", "green", "red"], height: 30 } as config));
console.log(
plot(
[heapUsageArr, heapTopArr, rssArr],
{ colors: ["blue", "green", "red"], height: 30 } as config,
),
);
2 changes: 1 addition & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export { SlashFields as Slash } from "./src/types/fields/slash_fields.ts";

export type { Options } from "./src/deserializer.ts";

export { parseFeed } from "./src/deserializer.ts";
export { parseFeed } from "./src/deserializer.ts";
9 changes: 4 additions & 5 deletions src/deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,8 @@ const parse = (input: string) =>
.trim();

if (attributes.length) {
cDataBuilder += `<${node.name} ${attributes}${(node.isSelfClosing
? " /"
: "")}>`;
cDataBuilder +=
`<${node.name} ${attributes}${(node.isSelfClosing ? " /" : "")}>`;
} else {
cDataBuilder += `<${node.name}${(node.isSelfClosing ? " /" : "")}>`;
}
Expand Down Expand Up @@ -235,12 +234,12 @@ const parse = (input: string) =>
onclosetag: undefined,
ontext: undefined,
oncdata: undefined,
onend: undefined
onend: undefined,
});

reject(new Error(`Invalid or unsupported feed format`));
}
}
};

parser
.write(input)
Expand Down
42 changes: 30 additions & 12 deletions src/deserializer_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { MediaRssFields } from "./types/fields/media_rss_fields.ts";
const atomTestSample = await Deno.readTextFile("./samples/atom.xml");
const rss1TestSample = await Deno.readTextFile("./samples/rss1.xml");
const rss2TestSample = await Deno.readTextFile("./samples/rss2.xml");
const rss2DublinCoreTestSample = await Deno.readTextFile("./samples/rss2_dublin-core.xml");
const rss2DublinCoreTestSample = await Deno.readTextFile(
"./samples/rss2_dublin-core.xml",
);

[
{
Expand Down Expand Up @@ -307,7 +309,11 @@ const rss2DublinCoreTestSample = await Deno.readTextFile("./samples/rss2_dublin-
{
name: "Items:[0]:ContentEncoded:Value",
getValue: (src: Feed) => src.entries[0].content?.value,
assert: [{ fn: assertEquals, expect: "<RSS2:Item:0:ConentEncoded:CData></RSS2:Item:0:ConentEncoded:CData>" }],
assert: [{
fn: assertEquals,
expect:
"<RSS2:Item:0:ConentEncoded:CData></RSS2:Item:0:ConentEncoded:CData>",
}],
},
{
name: "Items:[0]:Guid",
Expand Down Expand Up @@ -551,17 +557,17 @@ const rss2DublinCoreTestSample = await Deno.readTextFile("./samples/rss2_dublin-
},
{
name: "Category:Length",
getValue: (src: Feed) => src.categories.length,
getValue: (src: Feed) => src.categories?.length,
assert: [{ fn: assertEquals, expect: 2 }],
},
{
name: "Category:[0]:Term",
getValue: (src: Feed) => src.categories[0].term,
getValue: (src: Feed) => src.categories?.[0].term,
assert: [{ fn: assertEquals, expect: "ATOM:Category:0:Term" }],
},
{
name: "Category:[1]:Term",
getValue: (src: Feed) => src.categories[1].term,
getValue: (src: Feed) => src.categories?.[1].term,
assert: [{ fn: assertEquals, expect: "ATOM:Category:1:Term" }],
},
{
Expand Down Expand Up @@ -710,7 +716,9 @@ const rss2DublinCoreTestSample = await Deno.readTextFile("./samples/rss2_dublin-
},
{
name: "Entry:[2]:media:group - Nestd MediaRSS group",
getValue: (src: Feed) => src.entries[2]?.[MediaRss.Group]?.[MediaRss.Community]?.[MediaRss.Statistics]?.views,
getValue: (src: Feed) =>
src.entries[2]?.[MediaRss.Group]?.[MediaRss.Community]
?.[MediaRss.Statistics]?.views,
assert: [{
fn: assertEquals,
expect: "1337",
Expand All @@ -722,16 +730,22 @@ const rss2DublinCoreTestSample = await Deno.readTextFile("./samples/rss2_dublin-
workspace.tests.forEach((test) => {
Deno.test(`parseFeed:${workspace.name}:${test.name}`, () => {
const target = test.getValue(workspace.source);
test.assert.forEach((assertion) => assertion.fn(target, assertion.expect));
test.assert.forEach((assertion) =>
assertion.fn(target, assertion.expect)
);
});
});
});

Deno.test('Should throw error on invalid feed format', async () => {
await assertRejects(() => parseFeed('Invalid feed string'), Error, "Invalid or unsupported feed format");
Deno.test("Should throw error on invalid feed format", async () => {
await assertRejects(
() => parseFeed("Invalid feed string"),
Error,
"Invalid or unsupported feed format",
);
});

Deno.test('Should throw error on unsupported feed format', async () => {
Deno.test("Should throw error on unsupported feed format", async () => {
const futureRSSFormat = `
<?xml version="1.0" encoding="UTF-8"?>
<xrss version="X.0" xmlns:media="http://schema.loremipsumuru.com/xrss/">
Expand Down Expand Up @@ -766,5 +780,9 @@ Deno.test('Should throw error on unsupported feed format', async () => {
</channel>
</xrss>
`;
await assertRejects(() => parseFeed(futureRSSFormat), Error, "Type xrss is not supported");
});
await assertRejects(
() => parseFeed(futureRSSFormat),
Error,
"Type xrss is not supported",
);
});
5 changes: 3 additions & 2 deletions src/mappers/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,13 +282,14 @@ const mapRss2ToFeed = (rss: InternalRSS2): Feed => {

entry.comments = comments?.value;
entry.published = entry[DublinCoreFields.DateSubmitted] || pubDate?.value;
entry.publishedRaw = entry[DublinCoreFields.DateSubmittedRaw] || pubDateRaw?.value;
entry.publishedRaw = entry[DublinCoreFields.DateSubmittedRaw] ||
pubDateRaw?.value;
entry.updated = pubDate?.value;
entry.updatedRaw = item.pubDateRaw?.value;

if (item[Rss2Fields.ContentEncoded]?.value) {
entry.content = {
value: item[Rss2Fields.ContentEncoded]?.value
value: item[Rss2Fields.ContentEncoded]?.value,
};
}

Expand Down
12 changes: 6 additions & 6 deletions src/mappers/mapper_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,15 +356,15 @@ const composeRss2 = (
value: "RSS2:Channel:Item:2:FeedburnerLink:Value",
},
"content:encoded": {
value: "RSS2:Channel:Item:2:content:encoded:Value"
}
value: "RSS2:Channel:Item:2:content:encoded:Value",
},
},
],
},
} as InternalRSS2;

DublinCoreFieldArray.forEach(
((dcField) => {
(dcField) => {
const fieldName = formatNamespaceFieldName(dcField);
const { isArray, isDate, isInt, isFloat } = resolveRss2Field(
dcField,
Expand Down Expand Up @@ -399,7 +399,7 @@ const composeRss2 = (

(result.channel as any)[dcField] = channelValue;
(result.channel.items[0] as any)[dcField] = itemValue;
}),
},
);

setter && setter(result);
Expand Down Expand Up @@ -453,7 +453,7 @@ const composeRss1 = (
} as InternalRSS1;

DublinCoreFieldArray.forEach(
((dcField) => {
(dcField) => {
const fieldName = formatNamespaceFieldName(dcField);
const { isArray, isInt, isFloat, isDate } = resolveRss1Field(
dcField,
Expand Down Expand Up @@ -484,7 +484,7 @@ const composeRss1 = (
{ value: `RSS1:Channel:${fieldName}:Value` };
(result.item[0] as any)[dcField] = itemValue ||
{ value: `RSS1:Item:0:${fieldName}:Value` };
}),
},
);

SlashFieldArray.forEach((slashField) => {
Expand Down
2 changes: 1 addition & 1 deletion src/types/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface Feed extends DublinCore {
copyright?: string;
author?: Author;
ttl?: number;
categories: Category[];
categories?: Category[];
skipHours?: number[];
skipDays?: string[];
image?: FeedImage;
Expand Down
4 changes: 2 additions & 2 deletions src/types/json_feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export interface JsonFeedItem {
date_modifiedRaw?: string;
authors?: JsonFeedAuthor[];
/**
* @deprecated Please use the new JsonFeed 1.1 authors field instead.
*/
* @deprecated Please use the new JsonFeed 1.1 authors field instead.
*/
author?: JsonFeedAuthor;
tags?: string[];
attachments?: Attachment[];
Expand Down
2 changes: 1 addition & 1 deletion test_deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export {
assert,
assertEquals,
assertNotEquals,
assertRejects
assertRejects,
} from "https://deno.land/[email protected]/assert/mod.ts";
Loading