UNPKG

take-shot

Version:
220 lines 8.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.injectCssRules = exports.embedWebFonts = exports.getWebFontCSS = void 0; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const util_1 = require("./util"); const dataurl_1 = require("./dataurl"); const embed_resources_1 = require("./embed-resources"); const cssFetchCache = {}; async function fetchCSS(url) { let cache = cssFetchCache[url]; if (cache != null) { return cache; } const res = await fetch(url); const cssText = await res.text(); cache = { url, cssText }; cssFetchCache[url] = cache; return cache; } async function embedFonts(data) { let cssText = data.cssText; const regexUrl = /url\(["']?([^"')]+)["']?\)/g; const fontLocs = cssText.match(/url\([^)]+\)/g) || []; const loadFonts = fontLocs.map(async (loc) => { let url = loc.replace(regexUrl, '$1'); if (!url.startsWith('https://')) { url = new URL(url, data.url).href; } return (0, dataurl_1.fetchAsDataURL)(url, ({ result }) => { cssText = cssText.replace(loc, `url(${result})`); return [loc, result]; }); }); return Promise.all(loadFonts).then(() => cssText); } function parseCSS(source) { if (source == null) { return []; } const result = []; const commentsRegex = /(\/\*[\s\S]*?\*\/)/gi; // strip out comments let cssText = source.replace(commentsRegex, ''); // eslint-disable-next-line prefer-regex-literals const keyframesRegex = new RegExp('((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})', 'gi'); // eslint-disable-next-line no-constant-condition while (true) { const matches = keyframesRegex.exec(cssText); if (matches === null) { break; } result.push(matches[0]); } cssText = cssText.replace(keyframesRegex, ''); const importRegex = /@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi; // to match css & media queries together const combinedCSSRegex = '((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]' + '*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})'; // unified regex const unifiedRegex = new RegExp(combinedCSSRegex, 'gi'); // eslint-disable-next-line no-constant-condition while (true) { let matches = importRegex.exec(cssText); if (matches === null) { matches = unifiedRegex.exec(cssText); if (matches === null) { break; } else { importRegex.lastIndex = unifiedRegex.lastIndex; } } else { unifiedRegex.lastIndex = importRegex.lastIndex; } result.push(matches[0]); } return result; } async function getCSSRules(styleSheets) { const ret = []; const deferreds = []; // First loop inlines imports styleSheets.forEach((sheet) => { if ('cssRules' in sheet) { try { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore (0, util_1.toArray)(sheet.cssRules || []).forEach((item, index) => { if (item.type === CSSRule.IMPORT_RULE) { let importIndex = index + 1; const url = item.href; const deferred = fetchCSS(url) .then((metadata) => embedFonts(metadata)) .then((cssText) => parseCSS(cssText).forEach((rule) => { try { sheet.insertRule(rule, rule.startsWith('@import') ? (importIndex += 1) : sheet.cssRules.length); } catch (error) { console.error('Error inserting rule from remote css', { rule, error }); } })) .catch((e) => { console.error('Error loading remote css', e.toString()); }); deferreds.push(deferred); } }); } catch (e) { const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0]; if (sheet.href != null) { deferreds.push(fetchCSS(sheet.href) .then((metadata) => embedFonts(metadata)) .then((cssText) => parseCSS(cssText).forEach((rule) => { inline.insertRule(rule, sheet.cssRules.length); })) .catch((err) => { console.error('Error loading remote stylesheet', err); })); } console.error('Error inlining remote css file', e); } } }); return Promise.all(deferreds).then(() => { // Second loop parses rules styleSheets.forEach((sheet) => { if ('cssRules' in sheet) { try { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore (0, util_1.toArray)(sheet.cssRules || []).forEach((item) => { ret.push(item); }); } catch (e) { console.error(`Error while reading CSS rules from ${sheet.href}`, e); } } }); return ret; }); } function getWebFontRules(cssRules) { return cssRules .filter((rule) => rule.type === CSSRule.FONT_FACE_RULE) .filter((rule) => (0, embed_resources_1.shouldEmbed)(rule.style.getPropertyValue('src'))); } const getStyleSheets = (node) => { if (node.ownerDocument == null) { throw new Error('Provided element is not within a Document'); } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return (0, util_1.toArray)(node.ownerDocument.styleSheets); }; const getStyleRuleList = (node) => getStyleSheets(node) ?.map((styleSheet) => (0, util_1.toArray)(styleSheet.cssRules).map(({ cssText }) => cssText)) // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore ?.flat(Infinity); async function parseWebFontRules(node) { const styleSheets = getStyleSheets(node); const cssRules = await getCSSRules(styleSheets); return getWebFontRules(cssRules); } async function getWebFontCSS(node, filterFontFace) { const rules = await parseWebFontRules(node); const _rules = filterFontFace && typeof filterFontFace === 'function' ? rules.filter(filterFontFace) : rules; if (_rules.length) { const cssTexts = await Promise.all(rules.map((rule) => { const baseUrl = rule.parentStyleSheet ? rule.parentStyleSheet.href : null; return (0, embed_resources_1.embedResources)(rule.cssText, baseUrl); })); return cssTexts.join('\n'); } } exports.getWebFontCSS = getWebFontCSS; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types async function embedWebFonts(clonedNode, filterFontFace) { const cssText = await getWebFontCSS(clonedNode, filterFontFace); if (cssText) { const styleNode = document.createElement('style'); const sytleContent = document.createTextNode(cssText); styleNode.appendChild(sytleContent); if (clonedNode.firstChild) { clonedNode.insertBefore(styleNode, clonedNode.firstChild); } else { clonedNode.appendChild(styleNode); } } } exports.embedWebFonts = embedWebFonts; const injectCssRules = (clonedNode, cssRuleSelector) => { const cssText = getStyleRuleList(clonedNode) ?.filter((rule) => { if (typeof cssRuleSelector === 'function') return cssRuleSelector(rule); return rule.includes('::-webkit-scrollbar') || rule.includes('scrollbar'); }) ?.join('\n'); if (cssText) { const styleNode = document.createElement('style'); const sytleContent = document.createTextNode(cssText); styleNode.appendChild(sytleContent); if (clonedNode.firstChild) { clonedNode.insertBefore(styleNode, clonedNode.firstChild); } else { clonedNode.appendChild(styleNode); } } }; exports.injectCssRules = injectCssRules; //# sourceMappingURL=embed-webfonts.js.map