Skip to content

Commit

Permalink
fix: make categories under Feed an optional type (#56)
Browse files Browse the repository at this point in the history
* style: apply deno fmt

* chore: configure vscode default formatter(deno fmt)

* fix: make categories under Feed an optional type
  • Loading branch information
totto2727 committed Mar 31, 2024
1 parent ebee31f commit a0817ec
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 46 deletions.
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";

0 comments on commit a0817ec

Please sign in to comment.