Happy TS proof-of-concept

This commit is contained in:
George Mandis 2021-11-28 00:55:38 -08:00
parent d207f805ab
commit b09146a7a0
3 changed files with 28 additions and 16 deletions

13
src/@types/bubo.d.ts vendored
View file

@ -7,5 +7,14 @@ export interface Feeds {
} }
export interface FeedItem { export interface FeedItem {
[key: string]: string | FeedItem[]; [key: string]: string | number | Date | FeedItem[];
} items: FeedItem[]
}
//NEW WAY
export type JSONValue =
| string
| number
| boolean
| { [x: string]: JSONValue }
| Array<JSONValue>;

View file

@ -39,16 +39,17 @@ for (const [group, feeds] of Object.entries(feedList)) {
// skip to the next one if this didn't work out // skip to the next one if this didn't work out
if (!body) continue; if (!body) continue;
const contents: any = const contents: FeedItem =
typeof body === "string" ? await parser.parseString(body) : body as { [key: string]: string }; (typeof body === "string" ? (await parser.parseString(body)) : body) as FeedItem;
contents.feed = feed; contents.feed = feed;
contents.title = getTitle(contents); contents.title = getTitle(contents);
contents.link = getLink(contents); contents.link = getLink(contents);
contentFromAllFeeds[group].push(contents); contentFromAllFeeds[group].push(contents as object);
// try to normalize date attribute naming // try to normalize date attribute naming
contents?.items?.forEach((item: { [key: string]: string }) => { contents?.items?.forEach((item) => {
item.timestamp = getTimestamp(item); item.timestamp = getTimestamp(item);
item.title = getTitle(item); item.title = getTitle(item);
item.link = getLink(item); item.link = getLink(item);

View file

@ -8,32 +8,34 @@
import { Response } from "node-fetch"; import { Response } from "node-fetch";
import { readFile } from "fs/promises"; import { readFile } from "fs/promises";
import { FeedItem, JSONValue } from "./@types/bubo";
export const getLink = (obj: { [key: string]: string }): string => { export const getLink = (obj: FeedItem): string => {
const link_values: string[] = ["link", "url", "guid", "home_page_url"]; const link_values: string[] = ["link", "url", "guid", "home_page_url"];
const keys: string[] = Object.keys(obj); const keys: string[] = Object.keys(obj);
const link_property: string | undefined = link_values.find(link_value => keys.includes(link_value)); const link_property: string | undefined = link_values.find(link_value => keys.includes(link_value));
return link_property ? obj[link_property] : ""; return link_property ? obj[link_property] as string : "";
}; };
// fallback to URL for the title if not present (coupled to my template) // fallback to URL for the title if not present (coupled to my template)
export const getTitle = (obj: { [key: string]: string }): string => { export const getTitle = (obj: FeedItem): string => {
const title_values: string[] = ["title", "url", "link"]; // fallback to url/link as title if omitted const title_values: string[] = ["title", "url", "link"]; // fallback to url/link as title if omitted
const keys: string[] = Object.keys(obj); const keys: string[] = Object.keys(obj);
const title_property: string | undefined = title_values.find(title_value => keys.includes(title_value)); const title_property: string | undefined = title_values.find(title_value => keys.includes(title_value));
return title_property ? obj[title_property] : ""; return title_property ? obj[title_property] as string : "";
}; };
// More dependable way to get timestamps // More dependable way to get timestamps
export const getTimestamp = (obj: { [key: string]: string }): string => { export const getTimestamp = (obj: FeedItem): string => {
const timestamp: number = new Date(obj.pubDate || obj.isoDate || obj.date || obj.date_published).getTime(); const dateString: string = (obj.pubDate || obj.isoDate || obj.date || obj.date_published).toString();
return isNaN(timestamp) ? (obj.pubDate || obj.isoDate || obj.date || obj.date_published) : timestamp.toString(); const timestamp: number = new Date(dateString).getTime();
return isNaN(timestamp) ? dateString : timestamp.toString();
}; };
// parse RSS/XML or JSON feeds // parse RSS/XML or JSON feeds
export async function parseFeed(response: Response): Promise<{ [key: string]: string } | unknown> { export async function parseFeed(response: Response): Promise<JSONValue> {
const contentType = response.headers.get("content-type")?.split(";")[0]; const contentType = response.headers.get("content-type")?.split(";")[0];
if (!contentType) return {}; if (!contentType) return {};
@ -54,7 +56,7 @@ export async function parseFeed(response: Response): Promise<{ [key: string]: st
const jsonFeed = [contentType] const jsonFeed = [contentType]
.map(item => .map(item =>
["application/json", "application/feed+json"].includes(item) ? response.json() : false ["application/json", "application/feed+json"].includes(item) ? response.json() as Promise<JSONValue> : false
) )
.filter(_ => _)[0]; .filter(_ => _)[0];
@ -62,7 +64,7 @@ export async function parseFeed(response: Response): Promise<{ [key: string]: st
} }
export const getFeedList = async (): Promise<string> => { export const getFeedList = async (): Promise<JSONValue> => {
return JSON.parse( return JSON.parse(
(await readFile( (await readFile(
new URL("../config/feeds.json", import.meta.url) new URL("../config/feeds.json", import.meta.url)