single-file-core 1.0.9 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/modules/css-fonts-alt-minifier.js +8 -6
- package/package.json +1 -1
- package/single-file-core.js +125 -272
- package/single-file-helper.js +5 -1
|
@@ -212,11 +212,11 @@ async function processFontFaceRule(ruleData, fontInfo, fontDeclarations, fontTes
|
|
|
212
212
|
removedNodes.forEach(node => ruleData.block.children.remove(node));
|
|
213
213
|
const srcDeclaration = ruleData.block.children.filter(node => node.property == "src").tail;
|
|
214
214
|
if (srcDeclaration) {
|
|
215
|
-
await Promise.all(fontInfo.map(async
|
|
215
|
+
await Promise.all(fontInfo.map(async source => {
|
|
216
216
|
if (fontTests.has(source.src)) {
|
|
217
217
|
source.valid = fontTests.get(source.src);
|
|
218
218
|
} else {
|
|
219
|
-
if (FontFace) {
|
|
219
|
+
if (FontFace && source.fontUrl) {
|
|
220
220
|
const fontFace = new FontFace("test-font", source.src);
|
|
221
221
|
try {
|
|
222
222
|
let timeout;
|
|
@@ -225,9 +225,10 @@ async function processFontFaceRule(ruleData, fontInfo, fontDeclarations, fontTes
|
|
|
225
225
|
new Promise(resolve => timeout = globalThis.setTimeout(() => { source.valid = true; resolve(); }, FONT_MAX_LOAD_DELAY))
|
|
226
226
|
]);
|
|
227
227
|
} catch (error) {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
const urlNodes = cssTree.findAll(srcDeclaration.data, node => node.type == "Url");
|
|
229
|
+
const declarationFontURLs = Array.from(fontDeclarations).find(([node]) => urlNodes.includes(node) && node.value == source.fontUrl)[1];
|
|
230
|
+
if (declarationFontURLs.length) {
|
|
231
|
+
const fontURL = declarationFontURLs[0];
|
|
231
232
|
if (fontURL) {
|
|
232
233
|
const fontFace = new FontFace("test-font", "url(" + fontURL + ")");
|
|
233
234
|
try {
|
|
@@ -276,7 +277,7 @@ async function processFontFaceRule(ruleData, fontInfo, fontDeclarations, fontTes
|
|
|
276
277
|
stats.fonts.discarded -= fontInfo.length;
|
|
277
278
|
fontInfo.reverse();
|
|
278
279
|
try {
|
|
279
|
-
srcDeclaration.data.value = cssTree.parse(fontInfo.map(fontSource => fontSource.src).join(","), { context: "value" });
|
|
280
|
+
srcDeclaration.data.value = cssTree.parse(fontInfo.map(fontSource => fontSource.src).join(","), { context: "value", parseCustomProperty: true });
|
|
280
281
|
}
|
|
281
282
|
catch (error) {
|
|
282
283
|
// ignored
|
|
@@ -333,6 +334,7 @@ function createFontsDetailsInfo() {
|
|
|
333
334
|
}
|
|
334
335
|
|
|
335
336
|
function getURL(urlFunction) {
|
|
337
|
+
urlFunction = urlFunction.replace(/url\(-sf-url-original\\\(\\"(.*?)\\"\\\)\\ /g, "");
|
|
336
338
|
const urlMatch = urlFunction.match(REGEXP_URL_SIMPLE_QUOTES_FN) ||
|
|
337
339
|
urlFunction.match(REGEXP_URL_DOUBLE_QUOTES_FN) ||
|
|
338
340
|
urlFunction.match(REGEXP_URL_NO_QUOTES_FN);
|
package/package.json
CHANGED
package/single-file-core.js
CHANGED
|
@@ -1024,12 +1024,9 @@ class Processor {
|
|
|
1024
1024
|
|
|
1025
1025
|
resolveStyleAttributeURLs() {
|
|
1026
1026
|
this.doc.querySelectorAll("[style]").forEach(element => {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}
|
|
1031
|
-
styleContent = ProcessorHelper.resolveStylesheetURLs(styleContent, this.baseURI, this.workStyleElement, this.options.saveOriginalURLs);
|
|
1032
|
-
const declarationList = cssTree.parse(styleContent, { context: "declarationList" });
|
|
1027
|
+
const styleContent = element.getAttribute("style");
|
|
1028
|
+
const declarationList = cssTree.parse(styleContent, { context: "declarationList", parseCustomProperty: true });
|
|
1029
|
+
ProcessorHelper.resolveStylesheetURLs(declarationList, this.baseURI, this.workStyleElement);
|
|
1033
1030
|
this.styles.set(element, declarationList);
|
|
1034
1031
|
});
|
|
1035
1032
|
}
|
|
@@ -1066,16 +1063,7 @@ class Processor {
|
|
|
1066
1063
|
let stylesheet;
|
|
1067
1064
|
stylesheets.set(element, stylesheetInfo);
|
|
1068
1065
|
if (!options.blockStylesheets) {
|
|
1069
|
-
|
|
1070
|
-
if (!matchCharsetEquals(stylesheetContent, options.charset)) {
|
|
1071
|
-
options = Object.assign({}, options, { charset: getCharset(stylesheetContent) });
|
|
1072
|
-
stylesheetContent = await getStylesheetContent(element, baseURI, options, workStyleElement);
|
|
1073
|
-
}
|
|
1074
|
-
try {
|
|
1075
|
-
stylesheet = cssTree.parse(removeCssComments(stylesheetContent));
|
|
1076
|
-
} catch (error) {
|
|
1077
|
-
// ignored
|
|
1078
|
-
}
|
|
1066
|
+
stylesheet = await getStylesheet(element, baseURI, options, workStyleElement);
|
|
1079
1067
|
}
|
|
1080
1068
|
if (stylesheet && stylesheet.children) {
|
|
1081
1069
|
if (options.compressCSS) {
|
|
@@ -1087,16 +1075,20 @@ class Processor {
|
|
|
1087
1075
|
}
|
|
1088
1076
|
}
|
|
1089
1077
|
|
|
1090
|
-
async function
|
|
1091
|
-
let
|
|
1078
|
+
async function getStylesheet(element, baseURI, options, workStyleElement) {
|
|
1079
|
+
let stylesheet;
|
|
1092
1080
|
if (!options.blockStylesheets) {
|
|
1093
1081
|
if (element.tagName == "LINK") {
|
|
1094
|
-
|
|
1082
|
+
stylesheet = await ProcessorHelper.resolveLinkStylesheetURLs(element.href, baseURI, options, workStyleElement);
|
|
1095
1083
|
} else {
|
|
1096
|
-
|
|
1084
|
+
stylesheet = cssTree.parse(element.textContent, { context: "stylesheet", parseCustomProperty: true });
|
|
1085
|
+
const importFound = await ProcessorHelper.resolveImportURLs(stylesheet, baseURI, options, workStyleElement);
|
|
1086
|
+
if (importFound) {
|
|
1087
|
+
stylesheet = cssTree.parse(cssTree.generate(stylesheet), { context: "stylesheet", parseCustomProperty: true });
|
|
1088
|
+
}
|
|
1097
1089
|
}
|
|
1098
1090
|
}
|
|
1099
|
-
return
|
|
1091
|
+
return stylesheet;
|
|
1100
1092
|
}
|
|
1101
1093
|
}
|
|
1102
1094
|
|
|
@@ -1108,7 +1100,7 @@ class Processor {
|
|
|
1108
1100
|
frameElement.setAttribute("data", "data:text/html,");
|
|
1109
1101
|
} else {
|
|
1110
1102
|
const src = frameElement.getAttribute("src");
|
|
1111
|
-
if (this.options.saveOriginalURLs && !isDataURL(src)) {
|
|
1103
|
+
if (this.options.saveOriginalURLs && src && !isDataURL(src)) {
|
|
1112
1104
|
frameElement.setAttribute("data-sf-original-src", src);
|
|
1113
1105
|
}
|
|
1114
1106
|
frameElement.removeAttribute("src");
|
|
@@ -1275,8 +1267,8 @@ class Processor {
|
|
|
1275
1267
|
}
|
|
1276
1268
|
|
|
1277
1269
|
async processStyleAttributes() {
|
|
1278
|
-
return Promise.all([...this.styles].map(([,
|
|
1279
|
-
ProcessorHelper.processStyle(
|
|
1270
|
+
return Promise.all([...this.styles].map(([, stylesheet]) =>
|
|
1271
|
+
ProcessorHelper.processStyle(stylesheet, this.baseURI, this.options, this.cssVariables, this.batchRequest)
|
|
1280
1272
|
));
|
|
1281
1273
|
}
|
|
1282
1274
|
|
|
@@ -1426,11 +1418,7 @@ class Processor {
|
|
|
1426
1418
|
const stylesheetInfo = this.stylesheets.get(styleElement);
|
|
1427
1419
|
if (stylesheetInfo) {
|
|
1428
1420
|
this.stylesheets.delete(styleElement);
|
|
1429
|
-
|
|
1430
|
-
if (this.options.saveOriginalURLs) {
|
|
1431
|
-
stylesheetContent = replaceOriginalURLs(stylesheetContent);
|
|
1432
|
-
}
|
|
1433
|
-
styleElement.textContent = stylesheetContent;
|
|
1421
|
+
styleElement.textContent = generateStylesheetContent(stylesheetInfo.stylesheet, this.options);
|
|
1434
1422
|
if (stylesheetInfo.mediaText) {
|
|
1435
1423
|
styleElement.media = stylesheetInfo.mediaText;
|
|
1436
1424
|
}
|
|
@@ -1446,12 +1434,7 @@ class Processor {
|
|
|
1446
1434
|
if (stylesheetInfo.mediaText) {
|
|
1447
1435
|
styleElement.media = stylesheetInfo.mediaText;
|
|
1448
1436
|
}
|
|
1449
|
-
|
|
1450
|
-
if (this.options.saveOriginalURLs) {
|
|
1451
|
-
stylesheetContent = replaceOriginalURLs(stylesheetContent);
|
|
1452
|
-
styleElement.setAttribute("data-sf-original-href", linkElement.getAttribute("data-sf-original-href"));
|
|
1453
|
-
}
|
|
1454
|
-
styleElement.textContent = stylesheetContent;
|
|
1437
|
+
styleElement.textContent = generateStylesheetContent(stylesheetInfo.stylesheet, this.options);
|
|
1455
1438
|
linkElement.parentElement.replaceChild(styleElement, linkElement);
|
|
1456
1439
|
} else {
|
|
1457
1440
|
linkElement.remove();
|
|
@@ -1461,14 +1444,10 @@ class Processor {
|
|
|
1461
1444
|
|
|
1462
1445
|
replaceStyleAttributes() {
|
|
1463
1446
|
this.doc.querySelectorAll("[style]").forEach(element => {
|
|
1464
|
-
const
|
|
1465
|
-
if (
|
|
1447
|
+
const declarationList = this.styles.get(element);
|
|
1448
|
+
if (declarationList) {
|
|
1466
1449
|
this.styles.delete(element);
|
|
1467
|
-
|
|
1468
|
-
if (this.options.saveOriginalURLs) {
|
|
1469
|
-
styleContent = replaceOriginalURLs(styleContent);
|
|
1470
|
-
}
|
|
1471
|
-
element.setAttribute("style", styleContent);
|
|
1450
|
+
element.setAttribute("style", generateStylesheetContent(declarationList, this.options));
|
|
1472
1451
|
} else {
|
|
1473
1452
|
element.setAttribute("style", "");
|
|
1474
1453
|
}
|
|
@@ -1708,52 +1687,43 @@ class ProcessorHelper {
|
|
|
1708
1687
|
removedRules.forEach(cssRule => stylesheet.children.remove(cssRule));
|
|
1709
1688
|
}
|
|
1710
1689
|
|
|
1711
|
-
static async resolveImportURLs(
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1690
|
+
static async resolveImportURLs(stylesheet, baseURI, options, workStylesheet, importedStyleSheets = new Set()) {
|
|
1691
|
+
let importFound;
|
|
1692
|
+
ProcessorHelper.resolveStylesheetURLs(stylesheet, baseURI, workStylesheet);
|
|
1693
|
+
const imports = getImportFunctions(stylesheet);
|
|
1694
|
+
await Promise.all(imports.map(async node => {
|
|
1695
|
+
const urlNode = cssTree.find(node, node => node.type == "Url") || cssTree.find(node, node => node.type == "String");
|
|
1696
|
+
let resourceURL = normalizeURL(urlNode.value);
|
|
1697
|
+
if (!testIgnoredPath(resourceURL) && testValidPath(resourceURL)) {
|
|
1698
|
+
urlNode.value = util.EMPTY_RESOURCE;
|
|
1699
|
+
try {
|
|
1700
|
+
resourceURL = util.resolveURL(resourceURL, baseURI);
|
|
1701
|
+
} catch (error) {
|
|
1702
|
+
// ignored
|
|
1703
|
+
}
|
|
1704
|
+
if (testValidURL(resourceURL) && !importedStyleSheets.has(resourceURL)) {
|
|
1705
|
+
const content = await getStylesheetContent(resourceURL);
|
|
1706
|
+
resourceURL = content.resourceURL;
|
|
1707
|
+
content.data = getUpdatedResourceContent(resourceURL, content, options);
|
|
1708
|
+
if (content.data && content.data.match(/^<!doctype /i)) {
|
|
1709
|
+
content.data = "";
|
|
1724
1710
|
}
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
content.data = getUpdatedResourceContent(resourceURL, content, options);
|
|
1729
|
-
if (content.data && content.data.match(/^<!doctype /i)) {
|
|
1730
|
-
content.data = "";
|
|
1731
|
-
}
|
|
1732
|
-
let importedStylesheetContent = removeCssComments(content.data);
|
|
1733
|
-
if (options.compressCSS) {
|
|
1734
|
-
importedStylesheetContent = util.compressCSS(importedStylesheetContent);
|
|
1735
|
-
}
|
|
1736
|
-
importedStylesheetContent = wrapMediaQuery(importedStylesheetContent, match.media);
|
|
1737
|
-
if (stylesheetContent.includes(cssImport)) {
|
|
1738
|
-
const ancestorStyleSheets = new Set(importedStyleSheets);
|
|
1739
|
-
ancestorStyleSheets.add(resourceURL);
|
|
1740
|
-
importedStylesheetContent = await ProcessorHelper.resolveImportURLs(importedStylesheetContent, resourceURL, options, workStylesheet, ancestorStyleSheets);
|
|
1741
|
-
workStylesheet.textContent = importedStylesheetContent;
|
|
1742
|
-
if ((workStylesheet.sheet && workStylesheet.sheet.cssRules.length) || (!workStylesheet.sheet && importedStylesheetContent)) {
|
|
1743
|
-
stylesheetContent = stylesheetContent.replace(regExpCssImport, importedStylesheetContent);
|
|
1744
|
-
} else {
|
|
1745
|
-
stylesheetContent = stylesheetContent.replace(regExpCssImport, "");
|
|
1746
|
-
}
|
|
1747
|
-
}
|
|
1748
|
-
} else {
|
|
1749
|
-
stylesheetContent = stylesheetContent.replace(regExpCssImport, "");
|
|
1711
|
+
const mediaQueryListNode = cssTree.find(node, node => node.type == "MediaQueryList");
|
|
1712
|
+
if (mediaQueryListNode) {
|
|
1713
|
+
content.data = wrapMediaQuery(content.data, cssTree.generate(mediaQueryListNode));
|
|
1750
1714
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1715
|
+
const importedStylesheet = cssTree.parse(content.data, { context: "stylesheet", parseCustomProperty: true });
|
|
1716
|
+
const ancestorStyleSheets = new Set(importedStyleSheets);
|
|
1717
|
+
ancestorStyleSheets.add(resourceURL);
|
|
1718
|
+
await ProcessorHelper.resolveImportURLs(importedStylesheet, resourceURL, options, workStylesheet, ancestorStyleSheets);
|
|
1719
|
+
for (let keyName of Object.keys(importedStylesheet)) {
|
|
1720
|
+
node[keyName] = importedStylesheet[keyName];
|
|
1721
|
+
}
|
|
1722
|
+
importFound = true;
|
|
1753
1723
|
}
|
|
1754
1724
|
}
|
|
1755
1725
|
}));
|
|
1756
|
-
return
|
|
1726
|
+
return importFound;
|
|
1757
1727
|
|
|
1758
1728
|
async function getStylesheetContent(resourceURL) {
|
|
1759
1729
|
const content = await util.getContent(resourceURL, {
|
|
@@ -1790,13 +1760,10 @@ class ProcessorHelper {
|
|
|
1790
1760
|
}
|
|
1791
1761
|
}
|
|
1792
1762
|
|
|
1793
|
-
static resolveStylesheetURLs(
|
|
1794
|
-
const
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
}
|
|
1798
|
-
urlFunctions.map(urlFunction => {
|
|
1799
|
-
const originalResourceURL = matchURL(urlFunction);
|
|
1763
|
+
static resolveStylesheetURLs(stylesheet, baseURI, workStylesheet) {
|
|
1764
|
+
const urls = getUrlFunctions(stylesheet);
|
|
1765
|
+
urls.map(urlNode => {
|
|
1766
|
+
const originalResourceURL = urlNode.value;
|
|
1800
1767
|
let resourceURL = normalizeURL(originalResourceURL);
|
|
1801
1768
|
workStylesheet.textContent = "tmp { content:\"" + resourceURL + "\"}";
|
|
1802
1769
|
if (workStylesheet.sheet && workStylesheet.sheet.cssRules) {
|
|
@@ -1812,25 +1779,14 @@ class ProcessorHelper {
|
|
|
1812
1779
|
// ignored
|
|
1813
1780
|
}
|
|
1814
1781
|
}
|
|
1815
|
-
if (testValidURL(resolvedURL)
|
|
1816
|
-
|
|
1817
|
-
stylesheetContent = stylesheetContent.replace(getRegExp(urlFunction), originalResourceURL ? urlFunction.replace(originalResourceURL, resolvedURL) : "url(" + resolvedURL + ")");
|
|
1818
|
-
} catch (error) {
|
|
1819
|
-
// ignored
|
|
1820
|
-
}
|
|
1782
|
+
if (testValidURL(resolvedURL)) {
|
|
1783
|
+
urlNode.value = resolvedURL;
|
|
1821
1784
|
}
|
|
1822
1785
|
} else {
|
|
1823
|
-
|
|
1824
|
-
if (originalResourceURL) {
|
|
1825
|
-
newUrlFunction = urlFunction.replace(originalResourceURL, util.EMPTY_RESOURCE);
|
|
1826
|
-
} else {
|
|
1827
|
-
newUrlFunction = "url(" + util.EMPTY_RESOURCE + ")";
|
|
1828
|
-
}
|
|
1829
|
-
stylesheetContent = stylesheetContent.replace(getRegExp(urlFunction), newUrlFunction);
|
|
1786
|
+
urlNode.value = util.EMPTY_RESOURCE;
|
|
1830
1787
|
}
|
|
1831
1788
|
}
|
|
1832
1789
|
});
|
|
1833
|
-
return stylesheetContent;
|
|
1834
1790
|
}
|
|
1835
1791
|
|
|
1836
1792
|
static async resolveLinkStylesheetURLs(resourceURL, baseURI, options, workStylesheet) {
|
|
@@ -1858,12 +1814,12 @@ class ProcessorHelper {
|
|
|
1858
1814
|
if (content.data && content.data.match(/^<!doctype /i)) {
|
|
1859
1815
|
content.data = "";
|
|
1860
1816
|
}
|
|
1861
|
-
let
|
|
1862
|
-
|
|
1863
|
-
|
|
1817
|
+
let stylesheet = cssTree.parse(content.data, { context: "stylesheet", parseCustomProperty: true });
|
|
1818
|
+
const importFound = await ProcessorHelper.resolveImportURLs(stylesheet, resourceURL, options, workStylesheet);
|
|
1819
|
+
if (importFound) {
|
|
1820
|
+
stylesheet = cssTree.parse(cssTree.generate(stylesheet), { context: "stylesheet", parseCustomProperty: true });
|
|
1864
1821
|
}
|
|
1865
|
-
|
|
1866
|
-
return stylesheetContent;
|
|
1822
|
+
return stylesheet;
|
|
1867
1823
|
}
|
|
1868
1824
|
}
|
|
1869
1825
|
|
|
@@ -1876,7 +1832,7 @@ class ProcessorHelper {
|
|
|
1876
1832
|
removedRules.push(cssRule);
|
|
1877
1833
|
} else if (ruleData.block && ruleData.block.children) {
|
|
1878
1834
|
if (ruleData.type == "Rule") {
|
|
1879
|
-
promises.push(this.processStyle(ruleData
|
|
1835
|
+
promises.push(this.processStyle(ruleData, baseURI, options, cssVariables, batchRequest));
|
|
1880
1836
|
} else if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "supports")) {
|
|
1881
1837
|
promises.push(this.processStylesheet(ruleData.block.children, baseURI, options, cssVariables, batchRequest));
|
|
1882
1838
|
} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
|
|
@@ -1888,94 +1844,62 @@ class ProcessorHelper {
|
|
|
1888
1844
|
await Promise.all(promises);
|
|
1889
1845
|
|
|
1890
1846
|
async function processFontFaceRule(ruleData) {
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
replaceURLs(declaration, originalResourceURL, content);
|
|
1908
|
-
}
|
|
1847
|
+
const urls = getUrlFunctions(ruleData);
|
|
1848
|
+
await Promise.all(urls.map(async urlNode => {
|
|
1849
|
+
const originalResourceURL = urlNode.value;
|
|
1850
|
+
if (!options.blockFonts) {
|
|
1851
|
+
const resourceURL = normalizeURL(originalResourceURL);
|
|
1852
|
+
if (!testIgnoredPath(resourceURL) && testValidURL(resourceURL)) {
|
|
1853
|
+
let { content } = await batchRequest.addURL(resourceURL,
|
|
1854
|
+
{ asBinary: true, expectedType: "font", baseURI, blockMixedContent: options.blockMixedContent });
|
|
1855
|
+
let resourceURLs = options.fontDeclarations.get(urlNode);
|
|
1856
|
+
if (!resourceURLs) {
|
|
1857
|
+
resourceURLs = [];
|
|
1858
|
+
options.fontDeclarations.set(urlNode, resourceURLs);
|
|
1859
|
+
}
|
|
1860
|
+
resourceURLs.push(resourceURL);
|
|
1861
|
+
if (!isDataURL(resourceURL) && options.saveOriginalURLs) {
|
|
1862
|
+
urlNode.value = "-sf-url-original(" + JSON.stringify(originalResourceURL) + ") " + content;
|
|
1909
1863
|
} else {
|
|
1910
|
-
|
|
1864
|
+
urlNode.value = content;
|
|
1911
1865
|
}
|
|
1912
|
-
}
|
|
1866
|
+
}
|
|
1867
|
+
} else {
|
|
1868
|
+
urlNode.value = util.EMPTY_RESOURCE;
|
|
1913
1869
|
}
|
|
1914
1870
|
}));
|
|
1915
|
-
|
|
1916
|
-
function replaceURLs(declaration, oldURL, newURL) {
|
|
1917
|
-
declaration.value.children.forEach(token => {
|
|
1918
|
-
if (token.type == "Url" && util.removeQuotes(getCSSValue(token.value)) == oldURL) {
|
|
1919
|
-
token.value = newURL;
|
|
1920
|
-
}
|
|
1921
|
-
});
|
|
1922
|
-
}
|
|
1923
1871
|
}
|
|
1924
1872
|
}
|
|
1925
1873
|
|
|
1926
|
-
static async processStyle(
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
if (!originalResourceURL.startsWith("#")) {
|
|
1948
|
-
if (duplicate && options.groupDuplicateImages && rootFunction && util.getContentSize(content) < SINGLE_FILE_VARIABLE_MAX_SIZE) {
|
|
1949
|
-
const value = cssTree.parse("var(" + SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource + ")", { context: "value" }).children.head;
|
|
1950
|
-
tokens.push({ parent, token, value });
|
|
1951
|
-
variableDefined = true;
|
|
1952
|
-
} else {
|
|
1953
|
-
token.data.value = content;
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
});
|
|
1957
|
-
if (variableDefined) {
|
|
1958
|
-
cssVariables.set(indexResource, { content, url: originalResourceURL });
|
|
1959
|
-
tokens.forEach(({ parent, token, value }) => parent.replace(token, value));
|
|
1874
|
+
static async processStyle(ruleData, baseURI, options, cssVariables, batchRequest) {
|
|
1875
|
+
const urls = getUrlFunctions(ruleData);
|
|
1876
|
+
await Promise.all(urls.map(async urlNode => {
|
|
1877
|
+
const originalResourceURL = urlNode.value;
|
|
1878
|
+
if (!options.blockImages) {
|
|
1879
|
+
const resourceURL = normalizeURL(originalResourceURL);
|
|
1880
|
+
if (!testIgnoredPath(resourceURL) && testValidURL(resourceURL)) {
|
|
1881
|
+
let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
|
|
1882
|
+
{ asBinary: true, expectedType: "image", groupDuplicates: options.groupDuplicateImages });
|
|
1883
|
+
if (!originalResourceURL.startsWith("#")) {
|
|
1884
|
+
if (duplicate && options.groupDuplicateImages && util.getContentSize(content) < SINGLE_FILE_VARIABLE_MAX_SIZE) {
|
|
1885
|
+
const varNode = cssTree.parse("var(" + SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource + ")", { context: "value" });
|
|
1886
|
+
for (let keyName of Object.keys(varNode.children.head.data)) {
|
|
1887
|
+
urlNode[keyName] = varNode.children.head.data[keyName];
|
|
1888
|
+
}
|
|
1889
|
+
cssVariables.set(indexResource, { content, url: originalResourceURL });
|
|
1890
|
+
} else {
|
|
1891
|
+
if (!isDataURL(resourceURL) && options.saveOriginalURLs) {
|
|
1892
|
+
urlNode.value = "-sf-url-original(" + JSON.stringify(originalResourceURL) + ") " + content;
|
|
1893
|
+
} else {
|
|
1894
|
+
urlNode.value = content;
|
|
1960
1895
|
}
|
|
1961
1896
|
}
|
|
1962
|
-
} else {
|
|
1963
|
-
findURLToken(originalResourceURL, declaration.value.children, token => token.data.value = util.EMPTY_RESOURCE);
|
|
1964
1897
|
}
|
|
1965
|
-
}));
|
|
1966
|
-
}
|
|
1967
|
-
}));
|
|
1968
|
-
|
|
1969
|
-
function findURLToken(url, children, callback, depth = 0) {
|
|
1970
|
-
for (let token = children.head; token; token = token.next) {
|
|
1971
|
-
if (token.data.children) {
|
|
1972
|
-
findURLToken(url, token.data.children, callback, depth + 1);
|
|
1973
|
-
}
|
|
1974
|
-
if (token.data.type == "Url" && util.removeQuotes(getCSSValue(token.data.value)) == url) {
|
|
1975
|
-
callback(token, children, depth == 0);
|
|
1976
1898
|
}
|
|
1899
|
+
} else {
|
|
1900
|
+
urlNode.value = util.EMPTY_RESOURCE;
|
|
1977
1901
|
}
|
|
1978
|
-
}
|
|
1902
|
+
}));
|
|
1979
1903
|
}
|
|
1980
1904
|
|
|
1981
1905
|
static async processAttribute(resourceElements, attributeName, baseURI, options, expectedType, cssVariables, styles, batchRequest, processDuplicates, removeElementIfMissing) {
|
|
@@ -2033,7 +1957,7 @@ class ProcessorHelper {
|
|
|
2033
1957
|
if (expectedType == "image" && processDuplicates && duplicate && !isSVG && util.getContentSize(content) < SINGLE_FILE_VARIABLE_MAX_SIZE) {
|
|
2034
1958
|
if (ProcessorHelper.replaceImageSource(resourceElement, SINGLE_FILE_VARIABLE_NAME_PREFIX + indexResource, options)) {
|
|
2035
1959
|
cssVariables.set(indexResource, { content, url: originURL });
|
|
2036
|
-
const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList" });
|
|
1960
|
+
const declarationList = cssTree.parse(resourceElement.getAttribute("style"), { context: "declarationList", parseCustomProperty: true });
|
|
2037
1961
|
styles.set(resourceElement, declarationList);
|
|
2038
1962
|
} else {
|
|
2039
1963
|
resourceElement.setAttribute(attributeName, content);
|
|
@@ -2188,18 +2112,6 @@ const HTTP_URI_PREFIX = /^https?:\/\//;
|
|
|
2188
2112
|
const FILE_URI_PREFIX = /^file:\/\//;
|
|
2189
2113
|
const EMPTY_URL = /^https?:\/\/+\s*$/;
|
|
2190
2114
|
const NOT_EMPTY_URL = /^(https?:\/\/|file:\/\/|blob:).+/;
|
|
2191
|
-
const REGEXP_URL_FN = /(url\s*\(\s*'(.*?)'\s*\))|(url\s*\(\s*"(.*?)"\s*\))|(url\s*\(\s*(.*?)\s*\))/gi;
|
|
2192
|
-
const REGEXP_URL_SIMPLE_QUOTES_FN = /^url\s*\(\s*'(.*?)'\s*\)$/i;
|
|
2193
|
-
const REGEXP_URL_DOUBLE_QUOTES_FN = /^url\s*\(\s*"(.*?)"\s*\)$/i;
|
|
2194
|
-
const REGEXP_URL_NO_QUOTES_FN = /^url\s*\(\s*(.*?)\s*\)$/i;
|
|
2195
|
-
const REGEXP_IMPORT_FN = /(@import\s*url\s*\(\s*'(.*?)'\s*\)\s*(.*?)(;|$|}))|(@import\s*url\s*\(\s*"(.*?)"\s*\)\s*(.*?)(;|$|}))|(@import\s*url\s*\(\s*(.*?)\s*\)\s*(.*?)(;|$|}))|(@import\s*'(.*?)'\s*(.*?)(;|$|}))|(@import\s*"(.*?)"\s*(.*?)(;|$|}))|(@import\s*(.*?)\s*(.*?)(;|$|}))/gi;
|
|
2196
|
-
const REGEXP_IMPORT_URL_SIMPLE_QUOTES_FN = /@import\s*url\s*\(\s*'(.*?)'\s*\)\s*(.*?)(;|$|})/i;
|
|
2197
|
-
const REGEXP_IMPORT_URL_DOUBLE_QUOTES_FN = /@import\s*url\s*\(\s*"(.*?)"\s*\)\s*(.*?)(;|$|})/i;
|
|
2198
|
-
const REGEXP_IMPORT_URL_NO_QUOTES_FN = /@import\s*url\s*\(\s*(.*?)\s*\)\s*(.*?)(;|$|})/i;
|
|
2199
|
-
const REGEXP_IMPORT_SIMPLE_QUOTES_FN = /@import\s*'(.*?)'\s*(.*?)(;|$|})/i;
|
|
2200
|
-
const REGEXP_IMPORT_DOUBLE_QUOTES_FN = /@import\s*"(.*?)"\s*(.*?)(;|$|})/i;
|
|
2201
|
-
const REGEXP_IMPORT_NO_QUOTES_FN = /@import\s*(.*?)\s*(.*?)(;|$|})/i;
|
|
2202
|
-
const REGEXP_ESCAPE = /([{}()^$&.*?/+|[\\\\]|\]|-)/g;
|
|
2203
2115
|
|
|
2204
2116
|
function getUpdatedResourceContent(resourceURL, content, options) {
|
|
2205
2117
|
if (options.rootDocument && options.updatedResources[resourceURL]) {
|
|
@@ -2218,20 +2130,6 @@ function normalizeURL(url) {
|
|
|
2218
2130
|
}
|
|
2219
2131
|
}
|
|
2220
2132
|
|
|
2221
|
-
function getCSSValue(value) {
|
|
2222
|
-
if (typeof value == "string") {
|
|
2223
|
-
return value;
|
|
2224
|
-
} else {
|
|
2225
|
-
let result = "";
|
|
2226
|
-
try {
|
|
2227
|
-
result = cssTree.generate(value);
|
|
2228
|
-
} catch (error) {
|
|
2229
|
-
// ignored
|
|
2230
|
-
}
|
|
2231
|
-
return result;
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
|
|
2235
2133
|
function matchCharsetEquals(stylesheetContent, charset = UTF8_CHARSET) {
|
|
2236
2134
|
const stylesheetCharset = getCharset(stylesheetContent);
|
|
2237
2135
|
if (stylesheetCharset) {
|
|
@@ -2318,21 +2216,23 @@ function getLastSegment(url, replacementCharacter) {
|
|
|
2318
2216
|
return lastSegment;
|
|
2319
2217
|
}
|
|
2320
2218
|
|
|
2321
|
-
function
|
|
2322
|
-
return
|
|
2219
|
+
function getUrlFunctions(declarationList) {
|
|
2220
|
+
return cssTree.findAll(declarationList, node => node.type == "Url");
|
|
2323
2221
|
}
|
|
2324
2222
|
|
|
2325
|
-
function
|
|
2326
|
-
|
|
2327
|
-
if (unique) {
|
|
2328
|
-
return [...new Set(result)];
|
|
2329
|
-
} else {
|
|
2330
|
-
return result;
|
|
2331
|
-
}
|
|
2223
|
+
function getImportFunctions(declarationList) {
|
|
2224
|
+
return cssTree.findAll(declarationList, node => node.type == "Atrule" && node.name == "import");
|
|
2332
2225
|
}
|
|
2333
2226
|
|
|
2334
|
-
function
|
|
2335
|
-
|
|
2227
|
+
function generateStylesheetContent(stylesheet, options) {
|
|
2228
|
+
let stylesheetContent = cssTree.generate(stylesheet);
|
|
2229
|
+
if (options.compressCSS) {
|
|
2230
|
+
stylesheetContent = util.compressCSS(stylesheetContent);
|
|
2231
|
+
}
|
|
2232
|
+
if (options.saveOriginalURLs) {
|
|
2233
|
+
stylesheetContent = replaceOriginalURLs(stylesheetContent);
|
|
2234
|
+
}
|
|
2235
|
+
return stylesheetContent;
|
|
2336
2236
|
}
|
|
2337
2237
|
|
|
2338
2238
|
function findShortcutIcon(shortcutIcons) {
|
|
@@ -2341,30 +2241,12 @@ function findShortcutIcon(shortcutIcons) {
|
|
|
2341
2241
|
return shortcutIcons[0];
|
|
2342
2242
|
}
|
|
2343
2243
|
|
|
2344
|
-
function matchURL(stylesheetContent) {
|
|
2345
|
-
const match = stylesheetContent.match(REGEXP_URL_SIMPLE_QUOTES_FN) ||
|
|
2346
|
-
stylesheetContent.match(REGEXP_URL_DOUBLE_QUOTES_FN) ||
|
|
2347
|
-
stylesheetContent.match(REGEXP_URL_NO_QUOTES_FN);
|
|
2348
|
-
return match && match[1];
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
function addOriginalURLs(stylesheetContent) {
|
|
2352
|
-
return stylesheetContent.replace(REGEXP_URL_FN, function (match, _0, url, _1, url2, _2, url3) {
|
|
2353
|
-
url = url || url2 || url3;
|
|
2354
|
-
if (isDataURL(url)) {
|
|
2355
|
-
return match;
|
|
2356
|
-
} else {
|
|
2357
|
-
return "-sf-url-original(" + JSON.stringify(url) + ") " + match;
|
|
2358
|
-
}
|
|
2359
|
-
});
|
|
2360
|
-
}
|
|
2361
|
-
|
|
2362
2244
|
function isDataURL(url) {
|
|
2363
2245
|
return url && (url.startsWith(DATA_URI_PREFIX) || url.startsWith(BLOB_URI_PREFIX));
|
|
2364
2246
|
}
|
|
2365
2247
|
|
|
2366
2248
|
function replaceOriginalURLs(stylesheetContent) {
|
|
2367
|
-
return stylesheetContent.replace(
|
|
2249
|
+
return stylesheetContent.replace(/url\(-sf-url-original\\\(\\"(.*?)\\"\\\)\\ /g, "/* original URL: $1 */url(");
|
|
2368
2250
|
}
|
|
2369
2251
|
|
|
2370
2252
|
function testIgnoredPath(resourceURL) {
|
|
@@ -2379,35 +2261,6 @@ function testValidURL(resourceURL) {
|
|
|
2379
2261
|
return testValidPath(resourceURL) && (resourceURL.match(HTTP_URI_PREFIX) || resourceURL.match(FILE_URI_PREFIX) || resourceURL.startsWith(BLOB_URI_PREFIX)) && resourceURL.match(NOT_EMPTY_URL);
|
|
2380
2262
|
}
|
|
2381
2263
|
|
|
2382
|
-
function matchImport(stylesheetContent) {
|
|
2383
|
-
const match = stylesheetContent.match(REGEXP_IMPORT_URL_SIMPLE_QUOTES_FN) ||
|
|
2384
|
-
stylesheetContent.match(REGEXP_IMPORT_URL_DOUBLE_QUOTES_FN) ||
|
|
2385
|
-
stylesheetContent.match(REGEXP_IMPORT_URL_NO_QUOTES_FN) ||
|
|
2386
|
-
stylesheetContent.match(REGEXP_IMPORT_SIMPLE_QUOTES_FN) ||
|
|
2387
|
-
stylesheetContent.match(REGEXP_IMPORT_DOUBLE_QUOTES_FN) ||
|
|
2388
|
-
stylesheetContent.match(REGEXP_IMPORT_NO_QUOTES_FN);
|
|
2389
|
-
if (match) {
|
|
2390
|
-
const [, resourceURL, media] = match;
|
|
2391
|
-
return { resourceURL, media };
|
|
2392
|
-
}
|
|
2393
|
-
}
|
|
2394
|
-
|
|
2395
|
-
function removeCssComments(stylesheetContent) {
|
|
2396
|
-
try {
|
|
2397
|
-
return stylesheetContent.replace(/\/\*(.|[\r\n])*?\*\//g, "");
|
|
2398
|
-
} catch (error) {
|
|
2399
|
-
let start, end;
|
|
2400
|
-
do {
|
|
2401
|
-
start = stylesheetContent.indexOf("/*");
|
|
2402
|
-
end = stylesheetContent.indexOf("*/", start + 2);
|
|
2403
|
-
if (start != -1 && end != -1) {
|
|
2404
|
-
stylesheetContent = stylesheetContent.substring(0, start) + stylesheetContent.substr(end + 2);
|
|
2405
|
-
}
|
|
2406
|
-
} while (start != -1 && end != -1);
|
|
2407
|
-
return stylesheetContent;
|
|
2408
|
-
}
|
|
2409
|
-
}
|
|
2410
|
-
|
|
2411
2264
|
function wrapMediaQuery(stylesheetContent, mediaQuery) {
|
|
2412
2265
|
if (mediaQuery) {
|
|
2413
2266
|
return "@media " + mediaQuery + "{ " + stylesheetContent + " }";
|
package/single-file-helper.js
CHANGED
|
@@ -273,7 +273,11 @@ function getResourcesInfo(win, doc, element, options, data, elementHidden, compu
|
|
|
273
273
|
element.setAttribute(IMAGE_ATTRIBUTE_NAME, data.images.length - 1);
|
|
274
274
|
data.markedElements.push(element);
|
|
275
275
|
element.removeAttribute(LAZY_SRC_ATTRIBUTE_NAME);
|
|
276
|
-
|
|
276
|
+
try {
|
|
277
|
+
computedStyle = computedStyle || win.getComputedStyle(element);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
// ignored
|
|
280
|
+
}
|
|
277
281
|
if (computedStyle) {
|
|
278
282
|
imageData.size = getSize(win, element, computedStyle);
|
|
279
283
|
const boxShadow = computedStyle.getPropertyValue("box-shadow");
|