Skip to content

Commit

Permalink
feat(site): Choose site from a list for ease (#78)
Browse files Browse the repository at this point in the history
Users don't need to write a full URL for enumerated sites.
  • Loading branch information
5ouma committed Jun 14, 2024
1 parent 3ed4218 commit 10e3a9d
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 27 deletions.
18 changes: 14 additions & 4 deletions .github/assets/example/feeds.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,18 @@ xmlUrl = "https://feed2.com/rss"
name = "list 2"

[[lists.feeds]]
title = "feed 1"
xmlUrl = "https://feed1.com/rss"
title = "bluesky"
type = "bluesky"
id = "username"
[[lists.feeds]]
title = "feed 2"
xmlUrl = "https://feed2.com/rss"
title = "note"
type = "note"
id = "username"
[[lists.feeds]]
title = "reddit"
type = "reddit"
id = "subreddit-name"
[[lists.feeds]]
title = "sizu.me"
type = "sizu.me"
id = "username"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/feeds.toml
/outputs/
/coverage
/coverage.lcov
9 changes: 7 additions & 2 deletions src/libs/convert.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { stringify } from "@libs/xml";
import { parse } from "@std/toml";
import { transcodeXmlUrl } from "./sites.ts";
import type { Feed, List, Lists, OPMLOutline } from "../types/mod.ts";

export function convertFromTOML(data: string): Lists {
const lists: Lists = parse(data) as Lists;
lists.lists.map((list: List) => {
list.feeds.map((feed: Feed) => {
feed.xmlUrl = new URL(feed.xmlUrl);
feed.xmlUrl = feed.xmlUrl
? new URL(feed.xmlUrl)
: transcodeXmlUrl(feed.title, feed.type, feed.id);
});
});
return lists;
Expand All @@ -18,7 +21,9 @@ export function convertToOPML(list: List): string {
return {
"@title": feed.title,
"@text": feed.title,
"@xmlUrl": feed.xmlUrl,
"@xmlUrl": feed.xmlUrl
? new URL(feed.xmlUrl)
: transcodeXmlUrl(feed.title, feed.type, feed.id),
"@type": "rss",
};
}),
Expand Down
23 changes: 23 additions & 0 deletions src/libs/sites.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { site } from "../types/mod.ts";

const sites: site[] = [
{ type: "bluesky", url: new URL("https://bsky.app/profile/{id}/rss") },
{ type: "note", url: new URL("https://note.com/{id}/rss") },
{ type: "reddit", url: new URL("https://www.reddit.com/r/{id}/.rss") },
{ type: "sizu.me", url: new URL("https://sizu.me/{id}/rss") },
];

export function transcodeXmlUrl(
title: string,
type: string | undefined,
id: string | undefined,
): URL {
if (!type) throw new Error(`Parameter not set: "type" of "${title}"`);
if (!id) throw new Error(`Parameter not set: "id" of "${title}"`);

const url: URL | undefined = sites
.find((site: site) => site.type === type)?.url;
if (!url) throw new Error(`Site not found: "${type}" of "${title}"`);

return new URL(url.href.replace(encodeURI("{id}"), id));
}
4 changes: 3 additions & 1 deletion src/types/toml.ts → src/types/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ export type List = {
};
export type Feed = {
title: string;
xmlUrl: URL;
type?: string;
id?: string;
xmlUrl?: URL;
};
3 changes: 2 additions & 1 deletion src/types/mod.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./opml.ts";
export * from "./toml.ts";
export * from "./feed.ts";
export * from "./sites.ts";
4 changes: 4 additions & 0 deletions src/types/sites.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type site = {
type: string;
url: URL;
};
80 changes: 61 additions & 19 deletions test/libs/convert_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { assertEquals } from "@std/assert";
import { convertFromTOML, convertToOPML } from "../../src/libs/convert.ts";
import type { List, Lists } from "../../src/types/mod.ts";

Deno.test("Parse TOML", () => {
Deno.test("Parse TOML (RSS)", () => {
const toml = `
[[lists]]
name = "list name"
Expand All @@ -13,23 +13,45 @@ xmlUrl = "https://example.com/feed"
`;

const feeds: Lists = {
lists: [
{
name: "list name",
feeds: [
{
title: "feed title",
xmlUrl: new URL("https://example.com/feed"),
},
],
},
],
lists: [{
name: "list name",
feeds: [{
title: "feed title",
xmlUrl: new URL("https://example.com/feed"),
}],
}],
};

assertEquals(convertFromTOML(toml), feeds);
});

Deno.test("Parse TOML (Site)", () => {
const toml = `
[[lists]]
name = "list name"
[[lists.feeds]]
title = "feed title"
type = "bluesky"
id = "username"
`;

const feeds: Lists = {
lists: [{
name: "list name",
feeds: [{
title: "feed title",
type: "bluesky",
id: "username",
xmlUrl: new URL("https://bsky.app/profile/username/rss"),
}],
}],
};

assertEquals(convertFromTOML(toml), feeds);
});

Deno.test("Convert Lists to OPML", () => {
Deno.test("Convert Lists to OPML (RSS)", () => {
const xml = `\
<?xml version="1.0" encoding="UTF-8"?>
<opml version="2.0">
Expand All @@ -41,12 +63,32 @@ Deno.test("Convert Lists to OPML", () => {

const list: List = {
name: "list name",
feeds: [
{
title: "feed title",
xmlUrl: new URL("https://example.com/feed"),
},
],
feeds: [{
title: "feed title",
xmlUrl: new URL("https://example.com/feed"),
}],
};

assertEquals(convertToOPML(list), xml);
});

Deno.test("Convert Lists to OPML (Site)", () => {
const xml = `\
<?xml version="1.0" encoding="UTF-8"?>
<opml version="2.0">
<body>
<outline title="feed title" text="feed title" xmlUrl="https://bsky.app/profile/username/rss" type="rss"/>
</body>
</opml>
`;

const list: List = {
name: "list name",
feeds: [{
title: "feed title",
type: "bluesky",
id: "username",
}],
};

assertEquals(convertToOPML(list), xml);
Expand Down
45 changes: 45 additions & 0 deletions test/libs/sites_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { assertEquals } from "@std/assert";
import { transcodeXmlUrl } from "../../src/libs/sites.ts";
import type { Feed } from "../../src/types/mod.ts";

Deno.test("Get XML URL (Site)", () => {
const feed: Feed = {
title: "feed title",
type: "bluesky",
id: "username",
};
assertEquals(
transcodeXmlUrl(feed.title, feed.type, feed.id),
new URL("https://bsky.app/profile/username/rss"),
);
});

Deno.test("Get XML URL (type not set)", () => {
const feed: Feed = { title: "feed title", id: "username" };
try {
transcodeXmlUrl(feed.title, undefined, feed.id);
} catch (error) {
assertEquals(error.message, `Parameter not set: "type" of "${feed.title}"`);
}
});

Deno.test("Get XML URL (id not set)", () => {
const feed: Feed = { title: "feed title", type: "bluesky" };
try {
transcodeXmlUrl(feed.title, feed.type, undefined);
} catch (error) {
assertEquals(error.message, `Parameter not set: "id" of "${feed.title}"`);
}
});

Deno.test("Get XML URL (Site not found)", () => {
const feed: Feed = { title: "feed title", type: "unknown", id: "username" };
try {
transcodeXmlUrl(feed.title, feed.type, feed.id);
} catch (error) {
assertEquals(
error.message,
`Site not found: "${feed.type}" of "${feed.title}"`,
);
}
});

0 comments on commit 10e3a9d

Please sign in to comment.