Skip to content

Commit

Permalink
refactor(ts): Make deep file structures
Browse files Browse the repository at this point in the history
Separate files by their roles, and merge tests.
  • Loading branch information
5ouma committed Aug 10, 2024
1 parent f0af3d4 commit 0dcb260
Show file tree
Hide file tree
Showing 20 changed files with 233 additions and 218 deletions.
3 changes: 0 additions & 3 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
{
"$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json",
"fmt": { "exclude": ["LICENSE", ".github/**/*.md"] },
"test": { "include": ["src/", "test/"] },
"tasks": {
"gen": "deno run --allow-env --allow-read --allow-write ./src/main.ts",
"test": "deno test --allow-env --allow-read --allow-write --parallel --shuffle",
"cov": "deno task test --coverage && deno coverage --lcov > coverage.lcov"
},
"imports": {
"@5ouma/opml-generator/libs": "./src/libs/mod.ts",
"@5ouma/opml-generator/types": "./src/types/mod.ts",
"@libs/xml": "jsr:@libs/[email protected]",
"@std/assert": "jsr:@std/[email protected]",
"@std/cli": "jsr:@std/[email protected]",
Expand Down
40 changes: 0 additions & 40 deletions src/libs/convert.ts

This file was deleted.

29 changes: 0 additions & 29 deletions src/libs/io.ts

This file was deleted.

4 changes: 3 additions & 1 deletion src/libs/mod.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./io.ts";
export * from "./toml/io.ts";
export * from "./xml/io.ts";
export type { Lists } from "./types.ts";
15 changes: 15 additions & 0 deletions src/libs/toml/convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { parse } from "@std/toml";
import { transcodeXmlUrl } from "../utils/sites.ts";
import type { Feed, List, Lists } from "../types.ts";

export function convert(data: string): Lists {
const lists: Lists = parse(data) as Lists;
lists.lists.map((list: List) => {
list.feeds.map((feed: Feed) => {
feed.xmlUrl = feed.xmlUrl
? new URL(feed.xmlUrl)
: transcodeXmlUrl(feed.title, feed.type, feed.id);
});
});
return lists;
}
54 changes: 54 additions & 0 deletions src/libs/toml/convert_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { assertEquals } from "@std/assert";
import { convert } from "./convert.ts";
import type { Lists } from "../types.ts";

Deno.test("Parse TOML", async (t: Deno.TestContext) => {
await t.step("rss", () => {
const toml = `
[[lists]]
name = "list name"
[[lists.feeds]]
title = "feed title"
xmlUrl = "https://example.com/feed"
`;

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

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

await t.step("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(convert(toml), feeds);
});
});
15 changes: 15 additions & 0 deletions src/libs/toml/io.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { convert } from "./convert.ts";
import type { Lists } from "../types.ts";

export async function readTOML(file: string): Promise<Lists> {
try {
const data: string = await Deno.readTextFile(file);
return convert(data);
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
throw new Error(`file not found: "${file}"`);
} else if (error instanceof Deno.errors.PermissionDenied) {
throw new Error(`permission denied: "${file}"`);
} else throw error;
}
}
37 changes: 13 additions & 24 deletions test/libs/io_test.ts → src/libs/toml/io_test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { assertEquals, assertIsError } from "@std/assert";
import { join } from "@std/path";
import { readTOML, writeXML } from "@5ouma/opml-generator/libs";
import { convertFromTOML, convertToOPML } from "../../src/libs/convert.ts";
import type { Lists } from "@5ouma/opml-generator/types";
import { readTOML } from "./io.ts";
import type { Lists } from "../types.ts";

Deno.test("Read TOML", async (t: Deno.TestContext) => {
await t.step("normal", async () => {
Expand All @@ -15,11 +13,20 @@ title = "feed title"
xmlUrl = "https://example.com/feed"
`;

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

const file: string = await Deno.makeTempFile({ suffix: ".toml" });
await Deno.writeTextFile(file, toml);
const lists: Lists = await readTOML(file);

assertEquals(convertFromTOML(toml), lists);
assertEquals(await readTOML(file), lists);
});

await t.step("file not found", async () => {
Expand Down Expand Up @@ -48,21 +55,3 @@ xmlUrl = "https://example.com/feed"
}
});
});

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

const dir: string = await Deno.makeTempDir();
await writeXML(feeds, dir);
const data: string = await Deno.readTextFile(join(dir, "list-name.xml"));

assertEquals(convertToOPML(feeds.lists[0]), data);
});
7 changes: 7 additions & 0 deletions src/types/feed.ts → src/libs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ export type Feed = {
id?: string;
xmlUrl?: URL;
};

export type OPMLOutline = {
"@title": string;
"@text": string;
"@xmlUrl": URL;
"@type": "rss";
};
13 changes: 8 additions & 5 deletions src/libs/sites.ts → src/libs/utils/sites.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { join } from "@std/url";
import type { site } from "@5ouma/opml-generator/types";
type site = {
type: string;
url: URL;
};

const sites: site[] = [
{ type: "bluesky", url: new URL("https://bsky.app/profile/{id}/rss") },
{
type: "nitter",
url: join(
new URL(`https://${Deno.env.get("NITTER_DOMAIN") ?? "cdn.xcancel.com"}`),
"/search/rss?f=tweets&q={id}",
url: new URL(
`https://${
Deno.env.get("NITTER_DOMAIN") ?? "cdn.xcancel.com"
}/search/rss?f=tweets&q={id}`,
),
},
{ type: "note", url: new URL("https://note.com/{id}/rss") },
Expand Down
4 changes: 2 additions & 2 deletions test/libs/sites_test.ts → src/libs/utils/sites_test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assertEquals } from "@std/assert";
import { transcodeXmlUrl } from "../../src/libs/sites.ts";
import type { Feed } from "@5ouma/opml-generator/types";
import { transcodeXmlUrl } from "./sites.ts";
import type { Feed } from "../types.ts";

Deno.test("Get XML URL", async (t: Deno.TestContext) => {
await t.step("site", () => {
Expand Down
22 changes: 22 additions & 0 deletions src/libs/xml/convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { stringify } from "@libs/xml";
import { transcodeXmlUrl } from "../utils/sites.ts";
import type { Feed, List, OPMLOutline } from "../types.ts";

export function convert(list: List): string {
const body = {
outline: list.feeds.map((feed: Feed): OPMLOutline => {
return {
"@title": feed.title,
"@text": feed.title,
"@xmlUrl": feed.xmlUrl
? new URL(feed.xmlUrl)
: transcodeXmlUrl(feed.title, feed.type, feed.id),
"@type": "rss",
};
}),
};

return `<?xml version="1.0" encoding="UTF-8"?>
${stringify({ opml: { "@version": "2.0", body: [body] } })}
`;
}
47 changes: 47 additions & 0 deletions src/libs/xml/convert_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { assertEquals } from "@std/assert";
import { convert } from "./convert.ts";
import type { List } from "../types.ts";
Deno.test("Convert Lists to OPML", async (t: Deno.TestContext) => {
await t.step("rss", () => {
const xml = `\
<?xml version="1.0" encoding="UTF-8"?>
<opml version="2.0">
<body>
<outline title="feed title" text="feed title" xmlUrl="https://example.com/feed" type="rss"/>
</body>
</opml>
`;

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

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

await t.step("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(convert(list), xml);
});
});
16 changes: 16 additions & 0 deletions src/libs/xml/io.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { paramCase } from "@wok/case";
import { format } from "@std/path";
import { convert } from "./convert.ts";
import type { List, Lists } from "../types.ts";

export async function writeXML(feeds: Lists, dir: string): Promise<void> {
await Deno.mkdir(dir, { recursive: true });
feeds.lists.map(async (list: List) => {
const file: string = format({
dir: dir,
name: paramCase(list.name),
ext: ".xml",
});
await Deno.writeTextFile(file, convert(list));
});
}
30 changes: 30 additions & 0 deletions src/libs/xml/io_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { assertEquals } from "@std/assert";
import { join } from "@std/path";
import { writeXML } from "./io.ts";
import type { Lists } from "../types.ts";

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

const xml = `\
<?xml version="1.0" encoding="UTF-8"?>
<opml version="2.0">
<body>
<outline title="feed title" text="feed title" xmlUrl="https://example.com/feed" type="rss"/>
</body>
</opml>
`;

const dir: string = await Deno.makeTempDir();
await writeXML(lists, dir);

assertEquals(await Deno.readTextFile(join(dir, "list-name.xml")), xml);
});
Loading

0 comments on commit 0dcb260

Please sign in to comment.