diff --git a/README.md b/README.md index 4fbe344..5b36a52 100644 --- a/README.md +++ b/README.md @@ -12,24 +12,20 @@ yarn add parse-favicon ```js import { parseFavicon } from 'parse-favicon' -const pageUrl = 'https://github.com' +const pageURL = 'https://github.com' -parseFavicon(pageUrl, textFetcher, bufferFetcher) +parseFavicon(pageURL, textFetcher, bufferFetcher) .subscribe(icon => console.log(icon)) function textFetcher(url: string): Promise { - return fetch(resolveURL(url, pageUrl)) + return fetch(url) .then(res => res.text()) } function bufferFetcher(url: string): Promise { - return fetch(resolveURL(url, pageUrl)) + return fetch(url) .then(res => res.arrayBuffer()) } - -function resolveURL(url: string, base: string): string { - return new URL(url, base).href -} ``` ## API @@ -51,7 +47,7 @@ interface ISize { } function parseFavicon( - url: string + pageURL: string , textFetcher: TextFetcher , bufferFetcher?: BufferFetcher ): Observable diff --git a/src/index.ts b/src/index.ts index 69768ff..e7a6733 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,13 +11,26 @@ import { parseImage, IImage } from '@utils/parse-image.js' import { Observable } from 'rxjs' import { flatten, each } from 'iterable-operator' import { IIcon, TextFetcher, BufferFetcher } from './types.js' +import { Awaitable } from '@blackglory/prelude' export { IIcon, TextFetcher, BufferFetcher } from './types.js' export function parseFavicon( - url: string -, textFetcher: TextFetcher -, bufferFetcher?: BufferFetcher + pageURL: string +, _fetchText: TextFetcher +, _fetchBuffer?: BufferFetcher ): Observable { + const fetchText: TextFetcher = (url: string): Awaitable => { + const absoluteURL = new URL(url, pageURL).href + return _fetchText(absoluteURL) + } + const fetchBuffer: BufferFetcher | undefined = + _fetchBuffer + ? (url: string): Awaitable => { + const absoluteURL = new URL(url, pageURL).href + return _fetchBuffer(absoluteURL) + } + : undefined + return new Observable(observer => { parse(icon => observer.next(icon)) .then(() => observer.complete()) @@ -25,7 +38,7 @@ export function parseFavicon( }) async function parse(publish: (icon: IIcon) => void) { - const html = await textFetcher(url) + const html = await fetchText(pageURL) const icons = [ ...parseAppleTouchIcons(html) @@ -36,24 +49,24 @@ export function parseFavicon( , ...parseWindows8Tiles(html) ] - if (bufferFetcher) { + if (fetchBuffer) { const imagePromisePool = new Map>() icons.forEach(async icon => publish( - await tryUpdateIcon(bufferFetcher, imagePromisePool, icon) + await tryUpdateIcon(fetchBuffer, imagePromisePool, icon) )) const results = await Promise.all([ - parseIEConfig(html, textFetcher) - , parseManifest(html, textFetcher) + parseIEConfig(html, fetchText) + , parseManifest(html, fetchText) ]) each(flatten(results), async icon => { - publish(await tryUpdateIcon(bufferFetcher, imagePromisePool, icon)) + publish(await tryUpdateIcon(fetchBuffer, imagePromisePool, icon)) }) getDefaultIconUrls().forEach(async url => { if (!imagePromisePool.has(url)) { - imagePromisePool.set(url, fetchImage(bufferFetcher, url)) + imagePromisePool.set(url, fetchImage(fetchBuffer, url)) } const image = await imagePromisePool.get(url) if (image) { @@ -71,20 +84,23 @@ export function parseFavicon( icons.forEach(publish) const results = await Promise.all([ - parseIEConfig(html, textFetcher) - , parseManifest(html, textFetcher) + parseIEConfig(html, fetchText) + , parseManifest(html, fetchText) ]) each(flatten(results), publish) } } async function tryUpdateIcon( - bufferFetcher: BufferFetcher + fetchBuffer: BufferFetcher , imagePromisePool: Map> , icon: IIcon ): Promise { if (!imagePromisePool.has(icon.url)) { - imagePromisePool.set(icon.url, fetchImage(bufferFetcher, icon.url)) + imagePromisePool.set( + icon.url + , fetchImage(fetchBuffer, new URL(icon.url, pageURL).href) + ) } const image = await imagePromisePool.get(icon.url) if (image) { @@ -95,10 +111,10 @@ export function parseFavicon( } async function fetchImage( - bufferFetcher: BufferFetcher + fetchBuffer: BufferFetcher , url: string ): Promise { - const arrayBuffer = await getResultAsync(() => bufferFetcher(url)) + const arrayBuffer = await getResultAsync(() => fetchBuffer(url)) if (!arrayBuffer) return null const buffer = Buffer.from(arrayBuffer) diff --git a/src/parse-ie-config.ts b/src/parse-ie-config.ts index 706765d..5968dd2 100644 --- a/src/parse-ie-config.ts +++ b/src/parse-ie-config.ts @@ -10,10 +10,11 @@ import { extractAttributes } from '@utils/extract-attributes.js' import { IIcon, TextFetcher } from '@src/types.js' import { isElement } from 'extra-dom' import { flatten, toArray } from 'iterable-operator' +import { getResultAsync } from 'return-style' export async function parseIEConfig( html: string -, textFetcher: TextFetcher +, fetchText: TextFetcher ): Promise { const document = parseHTML(html) const configUrls = extractConfigURLs(document) @@ -21,20 +22,12 @@ export async function parseIEConfig( return toArray(flatten(icons)) async function extractIconsFromURL(url: string): Promise { - const text = await fetch(url) + const text = await getResultAsync(() => fetchText(url)) if (text) { return parseIEConfigIcons(text, url) } else { return [] } - - async function fetch(url: string): Promise { - try { - return await textFetcher(url) - } catch { - return null - } - } } } diff --git a/src/parse-manifest.ts b/src/parse-manifest.ts index c57fe67..5374af0 100644 --- a/src/parse-manifest.ts +++ b/src/parse-manifest.ts @@ -9,6 +9,7 @@ import { parseSpaceSeparatedSizes } from '@utils/parse-space-separated-sizes.js' import { IIcon, TextFetcher } from '@src/types.js' import { extractAttributes } from '@utils/extract-attributes.js' import { isObject, isArray, isString } from '@blackglory/prelude' +import { getResultAsync } from 'return-style' interface IManifest { icons: Array<{ @@ -20,12 +21,12 @@ interface IManifest { export async function parseManifest( html: string -, textFetcher: TextFetcher +, fetchText: TextFetcher ): Promise { const document = parseHTML(html) const manifestUrls = extractManifestURLs(document) const results = await map(manifestUrls, async url => { - const text = await fetch(url) + const text = await getResultAsync(() => fetchText(url)) if (text) { return extractManifestIcons(text, url) } else { @@ -33,14 +34,6 @@ export async function parseManifest( } }) return ([] as IIcon[]).concat(...results) - - async function fetch(url: string): Promise { - try { - return await textFetcher(url) - } catch { - return null - } - } } function isManifest(val: unknown): val is IManifest {