single-file-core 1.3.7 → 1.3.9

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.
@@ -100,19 +100,23 @@ function getProcessorHelperClass(utilInstance) {
100
100
  } else {
101
101
  key.urlNode.value = name;
102
102
  }
103
- resources.stylesheets.set(resources.stylesheets.size, { name, content: this.generateStylesheetContent(stylesheetInfo.stylesheet, options), url: stylesheetInfo.url });
103
+ resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet });
104
104
  } else {
105
105
  if (key.element.tagName.toUpperCase() == "LINK") {
106
106
  const linkElement = key.element;
107
107
  const name = "stylesheet_" + resources.stylesheets.size + ".css";
108
108
  linkElement.setAttribute("href", name);
109
- resources.stylesheets.set(resources.stylesheets.size, { name, content: this.generateStylesheetContent(stylesheetInfo.stylesheet, options), url: stylesheetInfo.url });
109
+ resources.stylesheets.set(resources.stylesheets.size, { name, stylesheet: stylesheetInfo.stylesheet });
110
110
  } else {
111
111
  const styleElement = key.element;
112
112
  styleElement.textContent = this.generateStylesheetContent(stylesheetInfo.stylesheet, options);
113
113
  }
114
114
  }
115
115
  }
116
+ for (const [, stylesheetResource] of resources.stylesheets) {
117
+ stylesheetResource.content = this.generateStylesheetContent(stylesheetResource.stylesheet, options);
118
+ stylesheetResource.stylesheet = null;
119
+ }
116
120
  }
117
121
 
118
122
  async resolveImportURLs(stylesheetInfo, baseURI, options, workStylesheet, resources, stylesheets) {
@@ -138,10 +142,13 @@ function getProcessorHelperClass(utilInstance) {
138
142
  mediaText = cssTree.generate(mediaQueryListNode);
139
143
  }
140
144
  const existingStylesheet = Array.from(stylesheets).find(([, stylesheetInfo]) => stylesheetInfo.resourceURL == resourceURL);
145
+ let stylesheet;
141
146
  if (existingStylesheet) {
147
+ stylesheet = existingStylesheet[1].stylesheet;
142
148
  stylesheets.set({ urlNode }, {
143
149
  url: resourceURL,
144
- stylesheet: existingStylesheet[1].stylesheet, scoped
150
+ stylesheet,
151
+ scoped
145
152
  });
146
153
  } else {
147
154
  const stylesheetInfo = {
@@ -152,9 +159,11 @@ function getProcessorHelperClass(utilInstance) {
152
159
  stylesheetInfo.url = resourceURL = content.resourceURL;
153
160
  content.data = getUpdatedResourceContent(resourceURL, options) || content.data;
154
161
  stylesheetInfo.stylesheet = cssTree.parse(content.data, { context: "stylesheet", parseCustomProperty: true });
162
+ stylesheet = stylesheetInfo.stylesheet;
155
163
  await this.resolveImportURLs(stylesheetInfo, resourceURL, options, workStylesheet, resources, stylesheets);
156
164
  stylesheets.set({ urlNode }, stylesheetInfo);
157
165
  }
166
+ urlNode.importedChildren = stylesheet.children;
158
167
  }
159
168
  }
160
169
  }
@@ -100,10 +100,11 @@ function process(doc, stylesheets, styles, options) {
100
100
  }));
101
101
  unusedFonts = fontsInfo.declared.filter(fontInfo => !filteredUsedFonts.has(fontInfo.fontFamily));
102
102
  }
103
+ const docChars = Array.from(new Set(docContent)).map(char => char.charCodeAt(0)).sort((value1, value2) => value1 - value2);
103
104
  stylesheets.forEach(stylesheetInfo => {
104
105
  const cssRules = stylesheetInfo.stylesheet.children;
105
106
  if (cssRules) {
106
- filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docContent);
107
+ filterUnusedFonts(cssRules, fontsInfo.declared, unusedFonts, filteredUsedFonts, docChars);
107
108
  stats.rules.discarded -= cssRules.size;
108
109
  }
109
110
  });
@@ -134,17 +135,19 @@ function getFontsInfo(cssRules, fontsInfo, options) {
134
135
  });
135
136
  }
136
137
 
137
- function filterUnusedFonts(cssRules, declaredFonts, unusedFonts, filteredUsedFonts, docContent) {
138
+ function filterUnusedFonts(cssRules, declaredFonts, unusedFonts, filteredUsedFonts, docChars) {
138
139
  const removedRules = [];
139
140
  for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
140
141
  const ruleData = cssRule.data;
141
- if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "supports" || ruleData.name == "layer") && ruleData.block && ruleData.block.children) {
142
- filterUnusedFonts(ruleData.block.children, declaredFonts, unusedFonts, filteredUsedFonts, docContent);
142
+ if (ruleData.type == "Atrule" && ruleData.name == "import" && ruleData.prelude && ruleData.prelude.children && ruleData.prelude.children.head.data.importedChildren) {
143
+ filterUnusedFonts(ruleData.prelude.children.head.data.importedChildren, declaredFonts, unusedFonts, filteredUsedFonts, docChars);
144
+ } else if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "supports" || ruleData.name == "layer") && ruleData.block && ruleData.block.children) {
145
+ filterUnusedFonts(ruleData.block.children, declaredFonts, unusedFonts, filteredUsedFonts, docChars);
143
146
  } else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
144
147
  const fontFamily = helper.normalizeFontFamily(getDeclarationValue(ruleData.block.children, "font-family"));
145
148
  if (fontFamily) {
146
149
  const unicodeRange = getDeclarationValue(ruleData.block.children, "unicode-range");
147
- if (unusedFonts.find(fontInfo => fontInfo.fontFamily == fontFamily) || !testUnicodeRange(docContent, unicodeRange) || !testUsedFont(ruleData, fontFamily, declaredFonts, filteredUsedFonts)) {
150
+ if (unusedFonts.find(fontInfo => fontInfo.fontFamily == fontFamily) || !testUnicodeRange(docChars, unicodeRange) || !testUsedFont(ruleData, fontFamily, declaredFonts, filteredUsedFonts)) {
148
151
  removedRules.push(cssRule);
149
152
  }
150
153
  }
@@ -373,45 +376,34 @@ function getDeclarationUnescapedValue(declarations, property, workStylesheet) {
373
376
  return "";
374
377
  }
375
378
 
376
- function testUnicodeRange(docContent, unicodeRange) {
379
+ function testUnicodeRange(docCharCodes, unicodeRange) {
377
380
  if (unicodeRange) {
378
381
  const unicodeRanges = unicodeRange.split(REGEXP_COMMA);
379
- let invalid;
380
382
  const result = unicodeRanges.filter(rangeValue => {
381
383
  const range = rangeValue.split(REGEXP_DASH);
382
- let regExpString;
383
384
  if (range.length == 2) {
384
385
  range[0] = transformRange(range[0]);
385
- regExpString = "[" + range[0] + "-" + transformRange("U+" + range[1]) + "]";
386
- }
387
- if (range.length == 1) {
386
+ range[1] = transformRange(range[1]);
387
+ } else if (range.length == 1) {
388
388
  if (range[0].includes("?")) {
389
- const firstRange = transformRange(range[0]);
389
+ const firstRange = range[0];
390
390
  const secondRange = firstRange;
391
- regExpString = "[" + firstRange.replace(REGEXP_QUESTION_MARK, "0") + "-" + secondRange.replace(REGEXP_QUESTION_MARK, "F") + "]";
391
+ range[0] = transformRange(firstRange.replace(REGEXP_QUESTION_MARK, "0"));
392
+ range[1] = transformRange(secondRange.replace(REGEXP_QUESTION_MARK, "F"));
392
393
  } else if (range[0]) {
393
- regExpString = "[" + transformRange(range[0]) + "]";
394
+ range[0] = transformRange(range[0]);
394
395
  }
395
396
  }
396
- if (regExpString) {
397
- try {
398
- return (new RegExp(regExpString, "u")).test(docContent);
399
- } catch (error) {
400
- invalid = true;
401
- return false;
402
- }
397
+ if (!range[0] || docCharCodes.find(charCode => charCode >= range[0] && charCode <= range[1])) {
398
+ return true;
403
399
  }
404
- return true;
405
400
  });
406
- return !invalid && (!unicodeRanges.length || result.length);
401
+ return (!unicodeRanges.length || result.length);
407
402
  }
408
403
  return true;
409
404
  }
410
405
 
411
406
  function transformRange(range) {
412
407
  range = range.replace(REGEXP_STARTS_U_PLUS, "");
413
- while (range.length < 6) {
414
- range = "0" + range;
415
- }
416
- return "\\u{" + range + "}";
408
+ return parseInt(range, 16);
417
409
  }
@@ -40,16 +40,16 @@ class MatchedRules {
40
40
  doc.body.appendChild(workStyleSheet);
41
41
  const workStyleElement = doc.createElement("span");
42
42
  doc.body.appendChild(workStyleElement);
43
- stylesheets.forEach(stylesheetInfo => {
44
- if (!stylesheetInfo.scoped) {
43
+ stylesheets.forEach((stylesheetInfo, key) => {
44
+ if (!stylesheetInfo.scoped && !key.urlNode) {
45
45
  const cssRules = stylesheetInfo.stylesheet.children;
46
46
  if (cssRules) {
47
47
  if (stylesheetInfo.mediaText && stylesheetInfo.mediaText != MEDIA_ALL) {
48
48
  const mediaInfo = createMediaInfo(stylesheetInfo.mediaText);
49
49
  this.mediaAllInfo.medias.set("style-" + sheetIndex + "-" + stylesheetInfo.mediaText, mediaInfo);
50
- getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
50
+ getMatchedElementsRules(doc, cssRules, stylesheets, mediaInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
51
51
  } else {
52
- getMatchedElementsRules(doc, cssRules, this.mediaAllInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
52
+ getMatchedElementsRules(doc, cssRules, stylesheets, this.mediaAllInfo, sheetIndex, styles, matchedElementsCache, workStyleSheet);
53
53
  }
54
54
  }
55
55
  }
@@ -88,33 +88,41 @@ function getMediaAllInfo(doc, stylesheets, styles) {
88
88
  }
89
89
 
90
90
  function createMediaInfo(media) {
91
- const mediaInfo = { media: media, elements: new Map(), medias: new Map(), rules: new Map(), pseudoRules: new Map() };
91
+ const mediaInfo = {
92
+ media: media,
93
+ elements: new Map(),
94
+ medias: new Map(),
95
+ rules: new Map(),
96
+ pseudoRules: new Map()
97
+ };
92
98
  if (media == MEDIA_ALL) {
93
99
  mediaInfo.matchedStyles = new Map();
94
100
  }
95
101
  return mediaInfo;
96
102
  }
97
103
 
98
- function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet) {
99
- let mediaIndex = 0;
100
- let ruleIndex = 0;
104
+ function getMatchedElementsRules(doc, cssRules, stylesheets, mediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet, indexes = {
105
+ mediaIndex: 0, ruleIndex: 0
106
+ }) {
101
107
  let startTime;
102
108
  if (DEBUG && cssRules.length > 1) {
103
109
  startTime = Date.now();
104
110
  log(" -- STARTED getMatchedElementsRules", " index =", sheetIndex, "rules.length =", cssRules.length);
105
111
  }
106
112
  cssRules.forEach(ruleData => {
107
- if (ruleData.block && ruleData.block.children && ruleData.prelude && ruleData.prelude.children) {
113
+ if (ruleData.type == "Atrule" && ruleData.name == "import" && ruleData.prelude && ruleData.prelude.children && ruleData.prelude.children.head.data.importedChildren) {
114
+ getMatchedElementsRules(doc, ruleData.prelude.children.head.data.importedChildren, stylesheets, mediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet, indexes);
115
+ } else if (ruleData.block && ruleData.block.children && ruleData.prelude && ruleData.prelude.children) {
108
116
  if (ruleData.type == "Atrule" && ruleData.name == "media") {
109
117
  const mediaText = cssTree.generate(ruleData.prelude);
110
118
  const ruleMediaInfo = createMediaInfo(mediaText);
111
- mediaInfo.medias.set("rule-" + sheetIndex + "-" + mediaIndex + "-" + mediaText, ruleMediaInfo);
112
- mediaIndex++;
113
- getMatchedElementsRules(doc, ruleData.block.children, ruleMediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet);
119
+ mediaInfo.medias.set("rule-" + sheetIndex + "-" + indexes.mediaIndex + "-" + mediaText, ruleMediaInfo);
120
+ getMatchedElementsRules(doc, ruleData.block.children, stylesheets, ruleMediaInfo, sheetIndex, styles, matchedElementsCache, workStylesheet);
121
+ indexes.mediaIndex++;
114
122
  } else if (ruleData.type == "Rule") {
115
123
  const selectors = ruleData.prelude.children.toArray();
116
124
  const selectorsText = ruleData.prelude.children.toArray().map(selector => cssTree.generate(selector));
117
- const ruleInfo = { ruleData, mediaInfo, ruleIndex, sheetIndex, matchedSelectors: new Set(), declarations: new Set(), selectors, selectorsText };
125
+ const ruleInfo = { ruleData, mediaInfo, ruleIndex: indexes.ruleIndex, sheetIndex, matchedSelectors: new Set(), declarations: new Set(), selectors, selectorsText };
118
126
  if (!invalidSelector(selectorsText.join(","), workStylesheet) || selectorsText.find(selectorText => selectorText.includes("|"))) {
119
127
  for (let selector = ruleData.prelude.children.head, selectorIndex = 0; selector; selector = selector.next, selectorIndex++) {
120
128
  const selectorText = selectorsText[selectorIndex];
@@ -122,7 +130,7 @@ function getMatchedElementsRules(doc, cssRules, mediaInfo, sheetIndex, styles, m
122
130
  getMatchedElementsSelector(doc, selectorInfo, styles, matchedElementsCache);
123
131
  }
124
132
  }
125
- ruleIndex++;
133
+ indexes.ruleIndex++;
126
134
  }
127
135
  }
128
136
  });
@@ -178,7 +186,7 @@ function getFilteredSelector(selector, selectorText) {
178
186
  let namespaceFound;
179
187
  selector = { data: cssTree.parse(cssTree.generate(selector.data), { context: "selector" }) };
180
188
  filterNamespace(selector);
181
- if (namespaceFound) {
189
+ if (namespaceFound) {
182
190
  selectorText = cssTree.generate(selector.data).trim();
183
191
  }
184
192
  filterPseudoClasses(selector);
@@ -32,8 +32,8 @@ export {
32
32
  function process(stylesheets, styles, mediaAllInfo) {
33
33
  const stats = { processed: 0, discarded: 0 };
34
34
  let sheetIndex = 0;
35
- stylesheets.forEach(stylesheetInfo => {
36
- if (!stylesheetInfo.scoped) {
35
+ stylesheets.forEach((stylesheetInfo, key) => {
36
+ if (!stylesheetInfo.scoped && !key.urlNode) {
37
37
  const cssRules = stylesheetInfo.stylesheet.children;
38
38
  if (cssRules) {
39
39
  stats.processed += cssRules.size;
@@ -62,8 +62,8 @@ function process(stylesheets, styles, mediaAllInfo) {
62
62
  return stats;
63
63
  }
64
64
 
65
- function processRules(cssRules, sheetIndex, mediaInfo) {
66
- let mediaRuleIndex = 0, startTime;
65
+ function processRules(cssRules, sheetIndex, mediaInfo, indexes = { mediaRuleIndex: 0 }) {
66
+ let startTime;
67
67
  if (DEBUG && cssRules.size > 1) {
68
68
  startTime = Date.now();
69
69
  log(" -- STARTED processRules", "rules.length =", cssRules.size);
@@ -71,14 +71,13 @@ function processRules(cssRules, sheetIndex, mediaInfo) {
71
71
  const removedCssRules = [];
72
72
  for (let cssRule = cssRules.head; cssRule; cssRule = cssRule.next) {
73
73
  const ruleData = cssRule.data;
74
- if (ruleData.block && ruleData.block.children && ruleData.prelude && ruleData.prelude.children) {
74
+ if (ruleData.type == "Atrule" && ruleData.name == "import" && ruleData.prelude && ruleData.prelude.children && ruleData.prelude.children.head.data.importedChildren) {
75
+ processRules(ruleData.prelude.children.head.data.importedChildren, sheetIndex, mediaInfo, indexes);
76
+ } else if (ruleData.block && ruleData.block.children && ruleData.prelude && ruleData.prelude.children) {
75
77
  if (ruleData.type == "Atrule" && ruleData.name == "media") {
76
78
  const mediaText = cssTree.generate(ruleData.prelude);
77
- processRules(ruleData.block.children, sheetIndex, mediaInfo.medias.get("rule-" + sheetIndex + "-" + mediaRuleIndex + "-" + mediaText));
78
- if (!ruleData.prelude.children.size || !ruleData.block.children.size) {
79
- removedCssRules.push(cssRule);
80
- }
81
- mediaRuleIndex++;
79
+ processRules(ruleData.block.children, sheetIndex, mediaInfo.medias.get("rule-" + sheetIndex + "-" + indexes.mediaRuleIndex + "-" + mediaText));
80
+ indexes.mediaRuleIndex++;
82
81
  } else if (ruleData.type == "Rule") {
83
82
  const ruleInfo = mediaInfo.rules.get(ruleData);
84
83
  const pseudoSelectors = mediaInfo.pseudoRules.get(ruleData);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "single-file-core",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "SingleFile Core",
5
5
  "author": "Gildas Lormeau",
6
6
  "license": "AGPL-3.0-or-later",