diff --git a/src/@types/bubo.d.ts b/src/@types/bubo.d.ts index fcc47d1..a9c8452 100644 --- a/src/@types/bubo.d.ts +++ b/src/@types/bubo.d.ts @@ -7,5 +7,14 @@ export interface Feeds { } export interface FeedItem { - [key: string]: string | FeedItem[]; -} \ No newline at end of file + [key: string]: string | number | Date | FeedItem[]; + items: FeedItem[] +} + +//NEW WAY +export type JSONValue = + | string + | number + | boolean + | { [x: string]: JSONValue } + | Array; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index f5a8b56..bfa0433 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,16 +39,17 @@ for (const [group, feeds] of Object.entries(feedList)) { // skip to the next one if this didn't work out if (!body) continue; - const contents: any = - typeof body === "string" ? await parser.parseString(body) : body as { [key: string]: string }; + const contents: FeedItem = + (typeof body === "string" ? (await parser.parseString(body)) : body) as FeedItem; + contents.feed = feed; contents.title = getTitle(contents); contents.link = getLink(contents); - contentFromAllFeeds[group].push(contents); + contentFromAllFeeds[group].push(contents as object); // try to normalize date attribute naming - contents?.items?.forEach((item: { [key: string]: string }) => { + contents?.items?.forEach((item) => { item.timestamp = getTimestamp(item); item.title = getTitle(item); item.link = getLink(item); diff --git a/src/utilities.ts b/src/utilities.ts index 63ec2a1..b64a35d 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -8,32 +8,34 @@ import { Response } from "node-fetch"; 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 keys: string[] = Object.keys(obj); 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) -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 keys: string[] = Object.keys(obj); 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 -export const getTimestamp = (obj: { [key: string]: string }): string => { - const timestamp: number = new Date(obj.pubDate || obj.isoDate || obj.date || obj.date_published).getTime(); - return isNaN(timestamp) ? (obj.pubDate || obj.isoDate || obj.date || obj.date_published) : timestamp.toString(); +export const getTimestamp = (obj: FeedItem): string => { + const dateString: string = (obj.pubDate || obj.isoDate || obj.date || obj.date_published).toString(); + const timestamp: number = new Date(dateString).getTime(); + return isNaN(timestamp) ? dateString : timestamp.toString(); }; // parse RSS/XML or JSON feeds -export async function parseFeed(response: Response): Promise<{ [key: string]: string } | unknown> { +export async function parseFeed(response: Response): Promise { const contentType = response.headers.get("content-type")?.split(";")[0]; if (!contentType) return {}; @@ -54,7 +56,7 @@ export async function parseFeed(response: Response): Promise<{ [key: string]: st const jsonFeed = [contentType] .map(item => - ["application/json", "application/feed+json"].includes(item) ? response.json() : false + ["application/json", "application/feed+json"].includes(item) ? response.json() as Promise : false ) .filter(_ => _)[0]; @@ -62,7 +64,7 @@ export async function parseFeed(response: Response): Promise<{ [key: string]: st } -export const getFeedList = async (): Promise => { +export const getFeedList = async (): Promise => { return JSON.parse( (await readFile( new URL("../config/feeds.json", import.meta.url)