Spaces:
Build error
Build error
import { Options } from './types' | |
import { resolveUrl } from './util' | |
import { getMimeType } from './mimes' | |
import { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl' | |
const URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g | |
const URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g | |
const FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g | |
function toRegex(url: string): RegExp { | |
// eslint-disable-next-line no-useless-escape | |
const escaped = url.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1') | |
return new RegExp(`(url\\(['"]?)(${escaped})(['"]?\\))`, 'g') | |
} | |
export function parseURLs(cssText: string): string[] { | |
const urls: string[] = [] | |
cssText.replace(URL_REGEX, (raw, quotation, url) => { | |
urls.push(url) | |
return raw | |
}) | |
return urls.filter((url) => !isDataUrl(url)) | |
} | |
export async function embed( | |
cssText: string, | |
resourceURL: string, | |
baseURL: string | null, | |
options: Options, | |
getContentFromUrl?: (url: string) => Promise<string>, | |
): Promise<string> { | |
try { | |
const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL | |
const contentType = getMimeType(resourceURL) | |
let dataURL: string | |
if (getContentFromUrl) { | |
const content = await getContentFromUrl(resolvedURL) | |
dataURL = makeDataUrl(content, contentType) | |
} else { | |
dataURL = await resourceToDataURL(resolvedURL, contentType, options) | |
} | |
return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`) | |
} catch (error) { | |
// pass | |
} | |
return cssText | |
} | |
function filterPreferredFontFormat( | |
str: string, | |
{ preferredFontFormat }: Options, | |
): string { | |
return !preferredFontFormat | |
? str | |
: str.replace(FONT_SRC_REGEX, (match: string) => { | |
// eslint-disable-next-line no-constant-condition | |
while (true) { | |
const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [] | |
if (!format) { | |
return '' | |
} | |
if (format === preferredFontFormat) { | |
return `src: ${src};` | |
} | |
} | |
}) | |
} | |
export function shouldEmbed(url: string): boolean { | |
return url.search(URL_REGEX) !== -1 | |
} | |
export async function embedResources( | |
cssText: string, | |
baseUrl: string | null, | |
options: Options, | |
): Promise<string> { | |
if (!shouldEmbed(cssText)) { | |
return cssText | |
} | |
const filteredCSSText = filterPreferredFontFormat(cssText, options) | |
const urls = parseURLs(filteredCSSText) | |
return urls.reduce( | |
(deferred, url) => | |
deferred.then((css) => embed(css, url, baseUrl, options)), | |
Promise.resolve(filteredCSSText), | |
) | |
} | |