UNPKG

31.8 kBSource Map (JSON)View Raw
1{"version":3,"file":"use-atom-feed.esm.js","sources":["../src/Parser.ts","../src/index.guard.ts","../src/useAtomFeed.ts"],"sourcesContent":["import { AtomCategory, AtomContent, AtomLink, AtomLinkRelType, AtomPerson, AtomText, AtomTextType } from './AtomCommon';\nimport { AtomEntry, AtomSource } from './AtomEntry';\nimport { AtomFeed } from './AtomFeed';\n\nimport { sanitize } from 'dompurify';\n\n/** searches for a tag in the node list, prevents recursive searches */\nconst findByTag = (nodes: Iterable<Element> | ArrayLike<Element> | HTMLCollection, tagName: string) => Array.from(nodes).find(e => e.nodeName === tagName);\n/** searches for nodes which have a matching tagName, prevents recursive searches */\nconst filterByTag = (nodes: Iterable<Element> | ArrayLike<Element> | HTMLCollection, tagName: string) => Array.from(nodes).filter(e => e.nodeName === tagName);\n/** shortcut method for `findByTag()` that accesses children */\nconst findChildTag = (parent: Document | Element, tagName: string) => findByTag(parent.children, tagName);\n/** shortcut method for `filterByTag()` that accesses children */\nconst filterChildTags = (parent: Document | Element, tagName: string) => filterByTag(parent.children, tagName);\n\n/** parses the feed */\nexport function parseAtomFeed(data: string): AtomFeed {\n const parser = new DOMParser();\n const xml = parser.parseFromString(data, 'text/xml');\n const feed = findChildTag(xml, 'feed');\n if(feed) {\n return {\n id: sanitizeTextContent(findChildTag(feed, 'id')) ?? '',\n title: parseAtomText(findChildTag(feed, 'title')),\n updated: new Date(findChildTag(feed, 'updated')?.textContent ?? 0),\n entries: filterChildTags(feed, 'entry').map(e => parseAtomEntry(e)),\n author: filterChildTags(feed, 'author').map(author => parseAtomPerson(author)),\n link: filterChildTags(feed, 'link').map(link => parseAtomLink(link)),\n category: filterChildTags(feed, 'category').map(category => parseAtomCategory(category)),\n contributor: filterChildTags(feed, 'contributor').map(contributor => parseAtomPerson(contributor)),\n generator: {\n value: sanitizeTextContent(findChildTag(feed, 'generator')) ?? '',\n uri: sanitizeTextAttribute(findChildTag(feed, 'generator'), 'uri'),\n version: sanitizeTextAttribute(findChildTag(feed, 'generator'), 'version'),\n },\n icon: sanitizeTextContent(findChildTag(feed, 'icon')),\n logo: sanitizeTextContent(findChildTag(feed, 'logo')),\n rights: parseAtomText(findChildTag(feed, 'rights')),\n subtitle: sanitizeTextContent(findChildTag(feed, 'subtitle')),\n };\n }\n throw Error('No <feed> tag found.');\n}\n\nexport function parseAtomEntry(entry: Element): AtomEntry {\n return {\n id: sanitizeTextContent(findChildTag(entry, 'id')) ?? '',\n title: parseAtomText(findChildTag(entry, 'title')),\n updated: new Date(findChildTag(entry, 'updated')?.textContent ?? 0),\n author: filterChildTags(entry, 'author').map(author => parseAtomPerson(author)),\n content: parseAtomContent(findChildTag(entry, 'content')),\n link: filterChildTags(entry, 'link').map(link => parseAtomLink(link)),\n summary: parseAtomText(findChildTag(entry, 'summary')),\n category: filterChildTags(entry, 'category').map(category => parseAtomCategory(category)),\n contributor: filterChildTags(entry, 'contributor').map(contributor => parseAtomPerson(contributor)),\n published: findChildTag(entry, 'published') ? new Date(findChildTag(entry, 'published')?.textContent ?? 0) : undefined,\n rights: parseAtomText(findChildTag(entry, 'rights')),\n source: parseAtomSource(findChildTag(entry, 'source')),\n };\n}\n\n/** safely decode text content */\nexport function safelyDecodeAtomText(type: AtomTextType, element: Element | undefined): string {\n if(element !== undefined) {\n // If type=\"xhtml\", then this element contains inline xhtml, wrapped in a div element.\n // This means that the existing `.innerHTML` is ready to be santized\n if(type === 'xhtml') return sanitize(element.innerHTML);\n // If type=\"html\", then this element contains entity escaped html.\n // using `.textContent` will un-escape the text\n else if(type === 'html') return sanitize(element.textContent ?? '');\n // If type=\"text\", then this element contains plain text with no entity escaped html.\n // This means that the content of `.innerHTML` are **intended** to be safe.\n // However, we don't want to leave an attack vector open, so we're going to sanitize it anyway.\n else if(type === 'text') return sanitize(element.innerHTML);\n }\n return '';\n}\n\n/** shortcut for safely decoding the `.textContent` value of an element */\nexport function sanitizeTextContent(element: Element | undefined): string | undefined { \n return element !== undefined ? sanitize(element?.textContent ?? '') : undefined;\n}\n\n/** shortcut for safely decoding the an attribute value of an element */\nexport function sanitizeTextAttribute<T = string>(element: Element | undefined, attributeName: string): T | undefined {\n return element !== undefined ? (element.getAttribute(attributeName) !== null ? sanitize(element.getAttribute(attributeName)!) as unknown as T : undefined) : undefined;\n}\n\nexport function parseAtomContent(content: Element | undefined): AtomContent {\n const type = (sanitizeTextAttribute(content, 'type') as AtomTextType) ?? undefined;\n return {\n type,\n src: sanitizeTextAttribute(content, 'src'),\n value: safelyDecodeAtomText(type, content),\n }\n}\n\n\nexport function parseAtomText(text: Element | undefined): AtomText {\n const type = (sanitizeTextAttribute(text, 'type') as AtomTextType) ?? undefined;\n return {\n type,\n value: safelyDecodeAtomText(type, text)\n }\n}\n\nexport function parseAtomPerson(person: Element): AtomPerson {\n return {\n name: sanitize(findChildTag(person, 'name')?.textContent ?? ''),\n uri: sanitizeTextContent(findChildTag(person, 'uri')),\n email: sanitizeTextContent(findChildTag(person, 'email')),\n }\n}\n\nexport function parseAtomLink(link: Element): AtomLink {\n return {\n href: sanitizeTextAttribute(link, 'href') ?? '',\n rel: sanitizeTextAttribute<AtomLinkRelType>(link, 'ref'),\n type: sanitizeTextAttribute(link, 'type'),\n hreflang: sanitizeTextAttribute(link, 'hreflang'),\n title: sanitizeTextAttribute(link, 'title'),\n length: sanitizeTextAttribute(link, 'length'),\n };\n}\n\nexport function parseAtomCategory(category: Element): AtomCategory {\n return {\n term: sanitizeTextAttribute(category, 'term') ?? '',\n scheme: sanitizeTextAttribute(category, 'scheme') ?? undefined,\n label: sanitizeTextAttribute(category, 'label') ?? undefined\n };\n}\n\nexport function parseAtomSource(source: Element | undefined): AtomSource | undefined {\n if(source !== undefined) {\n return {\n id: sanitizeTextContent(findChildTag(source, 'id')) ?? '',\n title: sanitizeTextContent(findChildTag(source, 'title')) ?? '',\n updated: new Date(findChildTag(source, 'title')?.textContent ?? 0)\n };\n }\n return undefined;\n}","/*\n * Generated type guards for \"index.ts\".\n * WARNING: Do not manually change this file.\n */\nimport { AtomFeed, AtomGenerator, AtomEntry, AtomSource, AtomCategory, AtomContent, AtomLink, AtomPerson, AtomLinkRelType, AtomAuthor, AtomContributor, AtomText, AtomTextType, AtomTitle, AtomSummary, AtomRights } from \"./index\";\n\nexport function isAtomFeed(obj: any, _argumentName?: string): obj is AtomFeed {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.id === \"string\" &&\n isAtomTitle(obj.title) as boolean &&\n obj.updated instanceof Date &&\n Array.isArray(obj.entries) &&\n obj.entries.every((e: any) =>\n isAtomEntry(e) as boolean\n ) &&\n (typeof obj.author === \"undefined\" ||\n Array.isArray(obj.author) &&\n obj.author.every((e: any) =>\n isAtomAuthor(e) as boolean\n )) &&\n (typeof obj.link === \"undefined\" ||\n Array.isArray(obj.link) &&\n obj.link.every((e: any) =>\n isAtomLink(e) as boolean\n )) &&\n (typeof obj.category === \"undefined\" ||\n Array.isArray(obj.category) &&\n obj.category.every((e: any) =>\n isAtomCategory(e) as boolean\n )) &&\n (typeof obj.contributor === \"undefined\" ||\n Array.isArray(obj.contributor) &&\n obj.contributor.every((e: any) =>\n isAtomContributor(e) as boolean\n )) &&\n (typeof obj.generator === \"undefined\" ||\n isAtomGenerator(obj.generator) as boolean) &&\n (typeof obj.icon === \"undefined\" ||\n typeof obj.icon === \"string\") &&\n (typeof obj.logo === \"undefined\" ||\n typeof obj.logo === \"string\") &&\n (typeof obj.rights === \"undefined\" ||\n isAtomRights(obj.rights) as boolean) &&\n (typeof obj.subtitle === \"undefined\" ||\n typeof obj.subtitle === \"string\")\n )\n}\n\nexport function isAtomGenerator(obj: any, _argumentName?: string): obj is AtomGenerator {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.value === \"string\" &&\n (typeof obj.uri === \"undefined\" ||\n typeof obj.uri === \"string\") &&\n (typeof obj.version === \"undefined\" ||\n typeof obj.version === \"string\")\n )\n}\n\nexport function isAtomEntry(obj: any, _argumentName?: string): obj is AtomEntry {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.id === \"string\" &&\n isAtomTitle(obj.title) as boolean &&\n obj.updated instanceof Date &&\n (typeof obj.author === \"undefined\" ||\n Array.isArray(obj.author) &&\n obj.author.every((e: any) =>\n isAtomAuthor(e) as boolean\n )) &&\n (typeof obj.content === \"undefined\" ||\n isAtomContent(obj.content) as boolean) &&\n (typeof obj.link === \"undefined\" ||\n Array.isArray(obj.link) &&\n obj.link.every((e: any) =>\n isAtomLink(e) as boolean\n )) &&\n (typeof obj.summary === \"undefined\" ||\n isAtomSummary(obj.summary) as boolean) &&\n (typeof obj.category === \"undefined\" ||\n Array.isArray(obj.category) &&\n obj.category.every((e: any) =>\n isAtomCategory(e) as boolean\n )) &&\n (typeof obj.contributor === \"undefined\" ||\n Array.isArray(obj.contributor) &&\n obj.contributor.every((e: any) =>\n isAtomContributor(e) as boolean\n )) &&\n (typeof obj.published === \"undefined\" ||\n obj.published instanceof Date) &&\n (typeof obj.rights === \"undefined\" ||\n isAtomRights(obj.rights) as boolean) &&\n (typeof obj.source === \"undefined\" ||\n isAtomSource(obj.source) as boolean)\n )\n}\n\nexport function isAtomSource(obj: any, _argumentName?: string): obj is AtomSource {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.id === \"string\" &&\n typeof obj.title === \"string\" &&\n obj.updated instanceof Date\n )\n}\n\nexport function isAtomCategory(obj: any, _argumentName?: string): obj is AtomCategory {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.term === \"string\" &&\n (typeof obj.scheme === \"undefined\" ||\n typeof obj.scheme === \"string\") &&\n (typeof obj.label === \"undefined\" ||\n typeof obj.label === \"string\")\n )\n}\n\nexport function isAtomContent(obj: any, _argumentName?: string): obj is AtomContent {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n (typeof obj.type === \"undefined\" ||\n obj.type === \"text\" ||\n obj.type === \"html\" ||\n obj.type === \"xhtml\") &&\n (typeof obj.src === \"undefined\" ||\n typeof obj.src === \"string\") &&\n typeof obj.value === \"string\"\n )\n}\n\nexport function isAtomLink(obj: any, _argumentName?: string): obj is AtomLink {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.href === \"string\" &&\n (typeof obj.rel === \"undefined\" ||\n obj.rel === \"alternate\" ||\n obj.rel === \"enclosure\" ||\n obj.rel === \"related\" ||\n obj.rel === \"self\" ||\n obj.rel === \"via\") &&\n (typeof obj.type === \"undefined\" ||\n typeof obj.type === \"string\") &&\n (typeof obj.hreflang === \"undefined\" ||\n typeof obj.hreflang === \"string\") &&\n (typeof obj.title === \"undefined\" ||\n typeof obj.title === \"string\") &&\n (typeof obj.length === \"undefined\" ||\n typeof obj.length === \"string\")\n )\n}\n\nexport function isAtomPerson(obj: any, _argumentName?: string): obj is AtomPerson {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n typeof obj.name === \"string\" &&\n (typeof obj.uri === \"undefined\" ||\n typeof obj.uri === \"string\") &&\n (typeof obj.email === \"undefined\" ||\n typeof obj.email === \"string\")\n )\n}\n\nexport function isAtomLinkRelType(obj: any, _argumentName?: string): obj is AtomLinkRelType {\n return (\n (obj === \"alternate\" ||\n obj === \"enclosure\" ||\n obj === \"related\" ||\n obj === \"self\" ||\n obj === \"via\")\n )\n}\n\nexport function isAtomAuthor(obj: any, _argumentName?: string): obj is AtomAuthor {\n return (\n isAtomPerson(obj) as boolean\n )\n}\n\nexport function isAtomContributor(obj: any, _argumentName?: string): obj is AtomContributor {\n return (\n isAtomPerson(obj) as boolean\n )\n}\n\nexport function isAtomText(obj: any, _argumentName?: string): obj is AtomText {\n return (\n (obj !== null &&\n typeof obj === \"object\" ||\n typeof obj === \"function\") &&\n (typeof obj.type === \"undefined\" ||\n obj.type === \"text\" ||\n obj.type === \"html\" ||\n obj.type === \"xhtml\") &&\n typeof obj.value === \"string\"\n )\n}\n\nexport function isAtomTextType(obj: any, _argumentName?: string): obj is AtomTextType {\n return (\n (obj === \"text\" ||\n obj === \"html\" ||\n obj === \"xhtml\")\n )\n}\n\nexport function isAtomTitle(obj: any, _argumentName?: string): obj is AtomTitle {\n return (\n isAtomText(obj) as boolean\n )\n}\n\nexport function isAtomSummary(obj: any, _argumentName?: string): obj is AtomSummary {\n return (\n isAtomText(obj) as boolean\n )\n}\n\nexport function isAtomRights(obj: any, _argumentName?: string): obj is AtomRights {\n return (\n isAtomText(obj) as boolean\n )\n}\n","import useSWR, { SWRConfiguration } from 'swr';\nimport { parseFeed } from 'htmlparser2';\n\nexport interface Response<Data> {\n data?: Data;\n error?: Error;\n isValidating: boolean;\n}\n\nexport type Feed = ReturnType<typeof parseFeed>;\n\n/**\n * The React hook used for reading the Atom feed.\n * @param feedURL The URL of the Atom feed\n * @param options Options that are passed to `useSWR()` behind the scenes.\n * More info: https://swr.vercel.app/docs/options#options\n * @returns The decoded Atom feed or any errors seen along the way\n */\nexport function useAtomFeed(feedURL: string, options?: SWRConfiguration): Response<Feed> {\n const fetcher = (url: string) => fetch(url).then(res => res.text());\n const { data, error, isValidating } = useSWR(feedURL, fetcher, options);\n\n // if data is defined\n if(data) {\n // attempt to decode\n try {\n const decoded = parseFeed(data, { xmlMode: true });\n // return a good decode\n return {\n data: decoded,\n error,\n isValidating\n }\n }\n catch(parseError) {\n // return a decode failure\n return {\n data: undefined,\n error: parseError,\n isValidating\n }\n }\n }\n else {\n // data is undefined\n return {\n data: undefined,\n error,\n isValidating\n }\n }\n}\n"],"names":["findByTag","nodes","tagName","Array","from","find","e","nodeName","filterByTag","filter","findChildTag","parent","children","filterChildTags","parseAtomFeed","data","parser","DOMParser","xml","parseFromString","feed","id","sanitizeTextContent","title","parseAtomText","updated","Date","textContent","entries","map","parseAtomEntry","author","parseAtomPerson","link","parseAtomLink","category","parseAtomCategory","contributor","generator","value","uri","sanitizeTextAttribute","version","icon","logo","rights","subtitle","Error","entry","content","parseAtomContent","summary","published","undefined","source","parseAtomSource","safelyDecodeAtomText","type","element","sanitize","innerHTML","attributeName","getAttribute","src","text","person","name","email","href","rel","hreflang","length","term","scheme","label","isAtomFeed","obj","_argumentName","isAtomTitle","isArray","every","isAtomEntry","isAtomAuthor","isAtomLink","isAtomCategory","isAtomContributor","isAtomGenerator","isAtomRights","isAtomContent","isAtomSummary","isAtomSource","isAtomPerson","isAtomLinkRelType","isAtomText","isAtomTextType","useAtomFeed","feedURL","options","fetcher","url","fetch","then","res","useSWR","error","isValidating","decoded","parseFeed","xmlMode","parseError"],"mappings":"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"}
\No newline at end of file