darkreader 4.9.80 → 4.9.81

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.
Files changed (3) hide show
  1. package/README.md +0 -1
  2. package/darkreader.js +357 -242
  3. package/package.json +8 -11
package/README.md CHANGED
@@ -155,7 +155,6 @@ Step 2: change Firefox's settings.
155
155
  A warning page may appear. Click `Accept the Risk and Continue` to proceed.
156
156
  - Search for and set `extensions.webextensions.restrictedDomains` to an empty value.
157
157
  - Create `extensions.webextensions.addons-restricted-domains@mozilla.com.disabled` with `boolean` as type and set its value to `true`.
158
- - Set `extensions.quarantinedDomains.enabled` to `false`.
159
158
  - Set `privacy.resistFingerprinting.block_mozAddonManager` to `true`.
160
159
  - Restart Firefox.
161
160
 
package/darkreader.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dark Reader v4.9.80
2
+ * Dark Reader v4.9.81
3
3
  * https://darkreader.org/
4
4
  */
5
5
 
@@ -777,6 +777,98 @@
777
777
  };
778
778
  }
779
779
 
780
+ function getMatches(regex, input, group = 0) {
781
+ const matches = [];
782
+ let m;
783
+ while ((m = regex.exec(input))) {
784
+ matches.push(m[group]);
785
+ }
786
+ return matches;
787
+ }
788
+ function escapeRegExpSpecialChars(input) {
789
+ return input.replaceAll(/[\^$.*+?\(\)\[\]{}|\-\\]/g, "\\$&");
790
+ }
791
+ function getParenthesesRange(input, searchStartIndex = 0) {
792
+ return getOpenCloseRange(input, searchStartIndex, "(", ")", []);
793
+ }
794
+ function getOpenCloseRange(
795
+ input,
796
+ searchStartIndex,
797
+ openToken,
798
+ closeToken,
799
+ excludeRanges
800
+ ) {
801
+ let indexOf;
802
+ if (excludeRanges.length === 0) {
803
+ indexOf = (token, pos) => input.indexOf(token, pos);
804
+ } else {
805
+ indexOf = (token, pos) =>
806
+ indexOfExcluding(input, token, pos, excludeRanges);
807
+ }
808
+ const {length} = input;
809
+ let depth = 0;
810
+ let firstOpenIndex = -1;
811
+ for (let i = searchStartIndex; i < length; i++) {
812
+ if (depth === 0) {
813
+ const openIndex = indexOf(openToken, i);
814
+ if (openIndex < 0) {
815
+ break;
816
+ }
817
+ firstOpenIndex = openIndex;
818
+ depth++;
819
+ i = openIndex;
820
+ } else {
821
+ const closeIndex = indexOf(closeToken, i);
822
+ if (closeIndex < 0) {
823
+ break;
824
+ }
825
+ const openIndex = indexOf(openToken, i);
826
+ if (openIndex < 0 || closeIndex <= openIndex) {
827
+ depth--;
828
+ if (depth === 0) {
829
+ return {start: firstOpenIndex, end: closeIndex + 1};
830
+ }
831
+ i = closeIndex;
832
+ } else {
833
+ depth++;
834
+ i = openIndex;
835
+ }
836
+ }
837
+ }
838
+ return null;
839
+ }
840
+ function indexOfExcluding(input, search, position, excludeRanges) {
841
+ const i = input.indexOf(search, position);
842
+ const exclusion = excludeRanges.find((r) => i >= r.start && i < r.end);
843
+ if (exclusion) {
844
+ return indexOfExcluding(
845
+ input,
846
+ search,
847
+ exclusion.end,
848
+ excludeRanges
849
+ );
850
+ }
851
+ return i;
852
+ }
853
+ function splitExcluding(input, separator, excludeRanges) {
854
+ const parts = [];
855
+ let commaIndex = -1;
856
+ let currIndex = 0;
857
+ while (
858
+ (commaIndex = indexOfExcluding(
859
+ input,
860
+ separator,
861
+ currIndex,
862
+ excludeRanges
863
+ )) >= 0
864
+ ) {
865
+ parts.push(input.substring(currIndex, commaIndex).trim());
866
+ currIndex = commaIndex + 1;
867
+ }
868
+ parts.push(input.substring(currIndex).trim());
869
+ return parts;
870
+ }
871
+
780
872
  let anchor;
781
873
  const parsedURLCache = new Map();
782
874
  function fixBaseURL($url) {
@@ -828,21 +920,21 @@
828
920
  return url.pathname === location.pathname;
829
921
  }
830
922
 
831
- function iterateCSSRules(rules, iterate, onMediaRuleError) {
923
+ function iterateCSSRules(rules, iterate, onImportError) {
832
924
  forEach(rules, (rule) => {
833
- if (rule.selectorText) {
925
+ if (isStyleRule(rule)) {
834
926
  iterate(rule);
835
- } else if (rule.href) {
927
+ } else if (isImportRule(rule)) {
836
928
  try {
837
929
  iterateCSSRules(
838
930
  rule.styleSheet.cssRules,
839
931
  iterate,
840
- onMediaRuleError
932
+ onImportError
841
933
  );
842
934
  } catch (err) {
843
- onMediaRuleError && onMediaRuleError();
935
+ onImportError?.();
844
936
  }
845
- } else if (rule.media) {
937
+ } else if (isMediaRule(rule)) {
846
938
  const media = Array.from(rule.media);
847
939
  const isScreenOrAllOrQuery = media.some(
848
940
  (m) =>
@@ -854,12 +946,14 @@
854
946
  (m) => m.startsWith("print") || m.startsWith("speech")
855
947
  );
856
948
  if (isScreenOrAllOrQuery || !isPrintOrSpeech) {
857
- iterateCSSRules(rule.cssRules, iterate, onMediaRuleError);
949
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
858
950
  }
859
- } else if (rule.conditionText) {
951
+ } else if (isSupportsRule(rule)) {
860
952
  if (CSS.supports(rule.conditionText)) {
861
- iterateCSSRules(rule.cssRules, iterate, onMediaRuleError);
953
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
862
954
  }
955
+ } else if (isLayerRule(rule)) {
956
+ iterateCSSRules(rule.cssRules, iterate, onImportError);
863
957
  } else;
864
958
  });
865
959
  }
@@ -907,6 +1001,33 @@
907
1001
  });
908
1002
  }
909
1003
  }
1004
+ if (
1005
+ cssText.includes("background-color: ;") &&
1006
+ !style.getPropertyValue("background")
1007
+ ) {
1008
+ const parentRule = style.parentRule;
1009
+ if (isStyleRule(parentRule)) {
1010
+ const sourceCSSText =
1011
+ parentRule.parentStyleSheet?.ownerNode?.textContent;
1012
+ if (sourceCSSText) {
1013
+ let escapedSelector = escapeRegExpSpecialChars(
1014
+ parentRule.selectorText
1015
+ );
1016
+ escapedSelector = escapedSelector.replaceAll(
1017
+ /\s+/g,
1018
+ "\\s*"
1019
+ );
1020
+ escapedSelector = escapedSelector.replaceAll(/::/g, "::?");
1021
+ const regexp = new RegExp(
1022
+ `${escapedSelector}\\s*{[^}]*?background:\\s*([^;}]+)`
1023
+ );
1024
+ const match = sourceCSSText.match(regexp);
1025
+ if (match) {
1026
+ iterate("background", match[1]);
1027
+ }
1028
+ }
1029
+ }
1030
+ }
910
1031
  }
911
1032
  const cssURLRegex = /url\((('.*?')|(".*?")|([^\)]*?))\)/g;
912
1033
  const cssImportRegex =
@@ -935,14 +1056,92 @@
935
1056
  }
936
1057
  });
937
1058
  }
938
- const cssCommentsRegex = /\/\*[\s\S]*?\*\//g;
939
- function removeCSSComments$1($css) {
940
- return $css.replace(cssCommentsRegex, "");
941
- }
942
1059
  const fontFaceRegex = /@font-face\s*{[^}]*}/g;
943
1060
  function replaceCSSFontFace($css) {
944
1061
  return $css.replace(fontFaceRegex, "");
945
1062
  }
1063
+ const styleRules = new WeakSet();
1064
+ const importRules = new WeakSet();
1065
+ const mediaRules = new WeakSet();
1066
+ const supportsRules = new WeakSet();
1067
+ const layerRules = new WeakSet();
1068
+ function isStyleRule(rule) {
1069
+ if (!rule) {
1070
+ return false;
1071
+ }
1072
+ if (styleRules.has(rule)) {
1073
+ return true;
1074
+ }
1075
+ if (rule.selectorText) {
1076
+ styleRules.add(rule);
1077
+ return true;
1078
+ }
1079
+ return false;
1080
+ }
1081
+ function isImportRule(rule) {
1082
+ if (!rule) {
1083
+ return false;
1084
+ }
1085
+ if (styleRules.has(rule)) {
1086
+ return false;
1087
+ }
1088
+ if (importRules.has(rule)) {
1089
+ return true;
1090
+ }
1091
+ if (rule.href) {
1092
+ importRules.add(rule);
1093
+ return true;
1094
+ }
1095
+ return false;
1096
+ }
1097
+ function isMediaRule(rule) {
1098
+ if (!rule) {
1099
+ return false;
1100
+ }
1101
+ if (styleRules.has(rule)) {
1102
+ return false;
1103
+ }
1104
+ if (mediaRules.has(rule)) {
1105
+ return true;
1106
+ }
1107
+ if (rule.media) {
1108
+ mediaRules.add(rule);
1109
+ return true;
1110
+ }
1111
+ return false;
1112
+ }
1113
+ function isSupportsRule(rule) {
1114
+ if (!rule) {
1115
+ return false;
1116
+ }
1117
+ if (styleRules.has(rule)) {
1118
+ return false;
1119
+ }
1120
+ if (supportsRules.has(rule)) {
1121
+ return true;
1122
+ }
1123
+ if (rule.cssText.startsWith("@supports")) {
1124
+ supportsRules.add(rule);
1125
+ return true;
1126
+ }
1127
+ return false;
1128
+ }
1129
+ function isLayerRule(rule) {
1130
+ if (!rule) {
1131
+ return false;
1132
+ }
1133
+ if (styleRules.has(rule)) {
1134
+ return false;
1135
+ }
1136
+ if (layerRules.has(rule)) {
1137
+ return true;
1138
+ }
1139
+ if (rule.cssText.startsWith("@layer") && rule.cssRules) {
1140
+ layerRules.add(rule);
1141
+ return true;
1142
+ }
1143
+ return false;
1144
+ }
946
1145
 
947
1146
  function evalMath(expression) {
948
1147
  const rpnStack = [];
@@ -1006,94 +1205,8 @@
1006
1205
  ["/", new Operator(2, (left, right) => left / right)]
1007
1206
  ]);
1008
1207
 
1009
- function getMatches(regex, input, group = 0) {
1010
- const matches = [];
1011
- let m;
1012
- while ((m = regex.exec(input))) {
1013
- matches.push(m[group]);
1014
- }
1015
- return matches;
1016
- }
1017
- function getParenthesesRange(input, searchStartIndex = 0) {
1018
- return getOpenCloseRange(input, searchStartIndex, "(", ")", []);
1019
- }
1020
- function getOpenCloseRange(
1021
- input,
1022
- searchStartIndex,
1023
- openToken,
1024
- closeToken,
1025
- excludeRanges
1026
- ) {
1027
- let indexOf;
1028
- if (excludeRanges.length === 0) {
1029
- indexOf = (token, pos) => input.indexOf(token, pos);
1030
- } else {
1031
- indexOf = (token, pos) =>
1032
- indexOfExcluding(input, token, pos, excludeRanges);
1033
- }
1034
- const {length} = input;
1035
- let depth = 0;
1036
- let firstOpenIndex = -1;
1037
- for (let i = searchStartIndex; i < length; i++) {
1038
- if (depth === 0) {
1039
- const openIndex = indexOf(openToken, i);
1040
- if (openIndex < 0) {
1041
- break;
1042
- }
1043
- firstOpenIndex = openIndex;
1044
- depth++;
1045
- i = openIndex;
1046
- } else {
1047
- const closeIndex = indexOf(closeToken, i);
1048
- if (closeIndex < 0) {
1049
- break;
1050
- }
1051
- const openIndex = indexOf(openToken, i);
1052
- if (openIndex < 0 || closeIndex <= openIndex) {
1053
- depth--;
1054
- if (depth === 0) {
1055
- return {start: firstOpenIndex, end: closeIndex + 1};
1056
- }
1057
- i = closeIndex;
1058
- } else {
1059
- depth++;
1060
- i = openIndex;
1061
- }
1062
- }
1063
- }
1064
- return null;
1065
- }
1066
- function indexOfExcluding(input, search, position, excludeRanges) {
1067
- const i = input.indexOf(search, position);
1068
- const exclusion = excludeRanges.find((r) => i >= r.start && i < r.end);
1069
- if (exclusion) {
1070
- return indexOfExcluding(
1071
- input,
1072
- search,
1073
- exclusion.end,
1074
- excludeRanges
1075
- );
1076
- }
1077
- return i;
1078
- }
1079
- function splitExcluding(input, separator, excludeRanges) {
1080
- const parts = [];
1081
- let commaIndex = -1;
1082
- let currIndex = 0;
1083
- while (
1084
- (commaIndex = indexOfExcluding(
1085
- input,
1086
- separator,
1087
- currIndex,
1088
- excludeRanges
1089
- )) >= 0
1090
- ) {
1091
- parts.push(input.substring(currIndex, commaIndex).trim());
1092
- currIndex = commaIndex + 1;
1093
- }
1094
- parts.push(input.substring(currIndex).trim());
1095
- return parts;
1096
- }
1208
+ const isSystemDarkModeEnabled = () =>
1209
+ matchMedia("(prefers-color-scheme: dark)").matches;
1097
1210
 
1098
1211
  const hslaParseCache = new Map();
1099
1212
  const rgbaParseCache = new Map();
@@ -1235,6 +1348,23 @@
1235
1348
  if ($color === "transparent") {
1236
1349
  return {r: 0, g: 0, b: 0, a: 0};
1237
1350
  }
1351
+ if (
1352
+ (c.startsWith("color(") || c.startsWith("color-mix(")) &&
1353
+ c.endsWith(")")
1354
+ ) {
1355
+ return domParseColor(c);
1356
+ }
1357
+ if (c.startsWith("light-dark(") && c.endsWith(")")) {
1358
+ const match = c.match(
1359
+ /^light-dark\(\s*([a-z]+(\(.*\))?),\s*([a-z]+(\(.*\))?)\s*\)$/
1360
+ );
1361
+ if (match) {
1362
+ const schemeColor = isSystemDarkModeEnabled()
1363
+ ? match[3]
1364
+ : match[1];
1365
+ return parse(schemeColor);
1366
+ }
1367
+ }
1238
1368
  return null;
1239
1369
  }
1240
1370
  function getNumbers($color) {
@@ -1548,6 +1678,21 @@
1548
1678
  function getSRGBLightness(r, g, b) {
1549
1679
  return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
1550
1680
  }
1681
+ let canvas$1;
1682
+ let context$1;
1683
+ function domParseColor($color) {
1684
+ if (!context$1) {
1685
+ canvas$1 = document.createElement("canvas");
1686
+ canvas$1.width = 1;
1687
+ canvas$1.height = 1;
1688
+ context$1 = canvas$1.getContext("2d", {willReadFrequently: true});
1689
+ }
1690
+ context$1.fillStyle = $color;
1691
+ context$1.fillRect(0, 0, 1, 1);
1692
+ const d = context$1.getImageData(0, 0, 1, 1).data;
1693
+ const color = `rgba(${d[0]}, ${d[1]}, ${d[2]}, ${(d[3] / 255).toFixed(2)})`;
1694
+ return parseRGB(color);
1695
+ }
1551
1696
 
1552
1697
  function scale(x, inLow, inHigh, outLow, outHigh) {
1553
1698
  return ((x - inLow) * (outHigh - outLow)) / (inHigh - inLow) + outLow;
@@ -2456,8 +2601,9 @@
2456
2601
  ignoreImageSelectors,
2457
2602
  isCancelled
2458
2603
  ) {
2604
+ let modifier = null;
2459
2605
  if (property.startsWith("--")) {
2460
- const modifier = getVariableModifier(
2606
+ modifier = getVariableModifier(
2461
2607
  variablesStore,
2462
2608
  property,
2463
2609
  value,
@@ -2465,30 +2611,16 @@
2465
2611
  ignoreImageSelectors,
2466
2612
  isCancelled
2467
2613
  );
2468
- if (modifier) {
2469
- return {
2470
- property,
2471
- value: modifier,
2472
- important: getPriority(rule.style, property),
2473
- sourceValue: value
2474
- };
2475
- }
2476
2614
  } else if (value.includes("var(")) {
2477
- const modifier = getVariableDependantModifier(
2615
+ modifier = getVariableDependantModifier(
2478
2616
  variablesStore,
2479
2617
  property,
2480
2618
  value
2481
2619
  );
2482
- if (modifier) {
2483
- return {
2484
- property,
2485
- value: modifier,
2486
- important: getPriority(rule.style, property),
2487
- sourceValue: value
2488
- };
2489
- }
2490
2620
  } else if (property === "color-scheme") {
2491
- return null;
2621
+ modifier = getColorSchemeModifier();
2622
+ } else if (property === "scrollbar-color") {
2623
+ modifier = getScrollbarColorModifier(value);
2492
2624
  } else if (
2493
2625
  (property.includes("color") &&
2494
2626
  property !== "-webkit-print-color-adjust") ||
@@ -2496,45 +2628,29 @@
2496
2628
  property === "stroke" ||
2497
2629
  property === "stop-color"
2498
2630
  ) {
2499
- const modifier = getColorModifier(property, value, rule);
2500
- if (modifier) {
2501
- return {
2502
- property,
2503
- value: modifier,
2504
- important: getPriority(rule.style, property),
2505
- sourceValue: value
2506
- };
2507
- }
2631
+ modifier = getColorModifier(property, value, rule);
2508
2632
  } else if (
2509
2633
  property === "background-image" ||
2510
2634
  property === "list-style-image"
2511
2635
  ) {
2512
- const modifier = getBgImageModifier(
2636
+ modifier = getBgImageModifier(
2513
2637
  value,
2514
2638
  rule,
2515
2639
  ignoreImageSelectors,
2516
2640
  isCancelled
2517
2641
  );
2518
- if (modifier) {
2519
- return {
2520
- property,
2521
- value: modifier,
2522
- important: getPriority(rule.style, property),
2523
- sourceValue: value
2524
- };
2525
- }
2526
2642
  } else if (property.includes("shadow")) {
2527
- const modifier = getShadowModifier(value);
2528
- if (modifier) {
2529
- return {
2530
- property,
2531
- value: modifier,
2532
- important: getPriority(rule.style, property),
2533
- sourceValue: value
2534
- };
2535
- }
2643
+ modifier = getShadowModifier(value);
2536
2644
  }
2537
- return null;
2645
+ if (!modifier) {
2646
+ return null;
2647
+ }
2648
+ return {
2649
+ property,
2650
+ value: modifier,
2651
+ important: getPriority(rule.style, property),
2652
+ sourceValue: value
2653
+ };
2538
2654
  }
2539
2655
  function joinSelectors(...selectors) {
2540
2656
  return selectors.filter(Boolean).join(", ");
@@ -2746,7 +2862,8 @@
2746
2862
  "initial",
2747
2863
  "currentcolor",
2748
2864
  "none",
2749
- "unset"
2865
+ "unset",
2866
+ "auto"
2750
2867
  ]);
2751
2868
  function getColorModifier(prop, value, rule) {
2752
2869
  if (unparsableColors.has(value.toLowerCase())) {
@@ -2766,14 +2883,14 @@
2766
2883
  (rule.style.getPropertyValue("mask-image") &&
2767
2884
  rule.style.getPropertyValue("mask-image") !== "none")
2768
2885
  ) {
2769
- return (filter) => modifyForegroundColor(rgb, filter);
2886
+ return (theme) => modifyForegroundColor(rgb, theme);
2770
2887
  }
2771
- return (filter) => modifyBackgroundColor(rgb, filter);
2888
+ return (theme) => modifyBackgroundColor(rgb, theme);
2772
2889
  }
2773
2890
  if (prop.includes("border") || prop.includes("outline")) {
2774
- return (filter) => modifyBorderColor(rgb, filter);
2891
+ return (theme) => modifyBorderColor(rgb, theme);
2775
2892
  }
2776
- return (filter) => modifyForegroundColor(rgb, filter);
2893
+ return (theme) => modifyForegroundColor(rgb, theme);
2777
2894
  }
2778
2895
  const imageDetailsCache = new Map();
2779
2896
  const awaitingForImageLoading = new Map();
@@ -3081,6 +3198,24 @@
3081
3198
  }
3082
3199
  return (theme) => shadowModifier(theme).result;
3083
3200
  }
3201
+ function getScrollbarColorModifier(value) {
3202
+ const colorsMatch = value.match(
3203
+ /^\s*([a-z]+(\(.*\))?)\s+([a-z]+(\(.*\))?)\s*$/
3204
+ );
3205
+ if (!colorsMatch) {
3206
+ return value;
3207
+ }
3208
+ const thumb = parseColorWithCache(colorsMatch[1]);
3209
+ const track = parseColorWithCache(colorsMatch[3]);
3210
+ if (!thumb || !track) {
3211
+ return null;
3212
+ }
3213
+ return (theme) =>
3214
+ `${modifyForegroundColor(thumb, theme)} ${modifyBackgroundColor(thumb, theme)}`;
3215
+ }
3216
+ function getColorSchemeModifier() {
3217
+ return (theme) => (theme.mode === 0 ? "dark light" : "dark");
3218
+ }
3084
3219
  function getVariableModifier(
3085
3220
  variablesStore,
3086
3221
  prop,
@@ -3196,7 +3331,9 @@
3196
3331
  this.unknownColorVars.has(ref) ||
3197
3332
  this.isVarType(
3198
3333
  ref,
3199
- VAR_TYPE_TEXTCOLOR | VAR_TYPE_BORDERCOLOR
3334
+ VAR_TYPE_BGCOLOR |
3335
+ VAR_TYPE_TEXTCOLOR |
3336
+ VAR_TYPE_BORDERCOLOR
3200
3337
  )
3201
3338
  );
3202
3339
  }) != null;
@@ -3419,21 +3556,20 @@
3419
3556
  return modified;
3420
3557
  }
3421
3558
  return new Promise((resolve) => {
3422
- const firstUnknownVar = unknownVars
3423
- .values()
3424
- .next().value;
3425
- const callback = () => {
3426
- this.unsubscribeFromVariableTypeChanges(
3427
- firstUnknownVar,
3559
+ for (const unknownVar of unknownVars.values()) {
3560
+ const callback = () => {
3561
+ this.unsubscribeFromVariableTypeChanges(
3562
+ unknownVar,
3563
+ callback
3564
+ );
3565
+ const newValue = modify();
3566
+ resolve(newValue);
3567
+ };
3568
+ this.subscribeForVarTypeChange(
3569
+ unknownVar,
3428
3570
  callback
3429
3571
  );
3430
- const newValue = modify();
3431
- resolve(newValue);
3432
- };
3433
- this.subscribeForVarTypeChange(
3434
- firstUnknownVar,
3435
- callback
3436
- );
3572
+ }
3437
3573
  });
3438
3574
  }
3439
3575
  return modified;
@@ -3520,8 +3656,11 @@
3520
3656
  return;
3521
3657
  }
3522
3658
  this.definedVars.add(varName);
3523
- const isColor =
3524
- rawValueRegex.test(value) || parseColorWithCache(value);
3659
+ const isColor = Boolean(
3660
+ value.match(rawRGBSpaceRegex) ||
3661
+ value.match(rawRGBCommaRegex) ||
3662
+ parseColorWithCache(value)
3663
+ );
3525
3664
  if (isColor) {
3526
3665
  this.unknownColorVars.add(varName);
3527
3666
  } else if (
@@ -3597,7 +3736,9 @@
3597
3736
  this.unknownColorVars.has(ref) ||
3598
3737
  this.isVarType(
3599
3738
  ref,
3600
- VAR_TYPE_TEXTCOLOR | VAR_TYPE_BORDERCOLOR
3739
+ VAR_TYPE_BGCOLOR |
3740
+ VAR_TYPE_TEXTCOLOR |
3741
+ VAR_TYPE_BORDERCOLOR
3601
3742
  )
3602
3743
  );
3603
3744
  }) != null;
@@ -3802,23 +3943,20 @@
3802
3943
  property === "-webkit-text-fill-color"
3803
3944
  );
3804
3945
  }
3805
- const rawValueRegex = /^\d{1,3}, ?\d{1,3}, ?\d{1,3}$/;
3806
- function parseRawValue(color) {
3807
- if (rawValueRegex.test(color)) {
3808
- const splitted = color.split(",");
3809
- let resultInRGB = "rgb(";
3810
- splitted.forEach((number) => {
3811
- resultInRGB += `${number.trim()}, `;
3812
- });
3813
- resultInRGB = resultInRGB.substring(0, resultInRGB.length - 2);
3814
- resultInRGB += ")";
3815
- return {isRaw: true, color: resultInRGB};
3946
+ const rawRGBSpaceRegex = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})$/;
3947
+ const rawRGBCommaRegex = /^(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})$/;
3948
+ function parseRawColorValue(input) {
3949
+ const match =
3950
+ input.match(rawRGBSpaceRegex) ?? input.match(rawRGBCommaRegex);
3951
+ if (match) {
3952
+ const color = `rgb(${match[1]}, ${match[2]}, ${match[3]})`;
3953
+ return {isRaw: true, color};
3816
3954
  }
3817
- return {isRaw: false, color: color};
3955
+ return {isRaw: false, color: input};
3818
3956
  }
3819
- function handleRawValue(color, theme, modifyFunction) {
3820
- const {isRaw, color: newColor} = parseRawValue(color);
3821
- const rgb = parseColorWithCache(newColor);
3957
+ function handleRawColorValue(input, theme, modifyFunction) {
3958
+ const {isRaw, color} = parseRawColorValue(input);
3959
+ const rgb = parseColorWithCache(color);
3822
3960
  if (rgb) {
3823
3961
  const outputColor = modifyFunction(rgb, theme);
3824
3962
  if (isRaw) {
@@ -3829,16 +3967,16 @@
3829
3967
  }
3830
3968
  return outputColor;
3831
3969
  }
3832
- return newColor;
3970
+ return color;
3833
3971
  }
3834
3972
  function tryModifyBgColor(color, theme) {
3835
- return handleRawValue(color, theme, modifyBackgroundColor);
3973
+ return handleRawColorValue(color, theme, modifyBackgroundColor);
3836
3974
  }
3837
3975
  function tryModifyTextColor(color, theme) {
3838
- return handleRawValue(color, theme, modifyForegroundColor);
3976
+ return handleRawColorValue(color, theme, modifyForegroundColor);
3839
3977
  }
3840
3978
  function tryModifyBorderColor(color, theme) {
3841
- return handleRawValue(color, theme, modifyBorderColor);
3979
+ return handleRawColorValue(color, theme, modifyBorderColor);
3842
3980
  }
3843
3981
  function insertVarValues(source, varValues, stack = new Set()) {
3844
3982
  let containsUnresolvedVar = false;
@@ -4408,6 +4546,11 @@
4408
4546
  }
4409
4547
  }
4410
4548
 
4549
+ const cssCommentsRegex = /\/\*[\s\S]*?\*\//g;
4550
+ function removeCSSComments(cssText) {
4551
+ return cssText.replace(cssCommentsRegex, "");
4552
+ }
4553
+
4411
4554
  const themeCacheKeys = [
4412
4555
  "mode",
4413
4556
  "brightness",
@@ -4461,9 +4604,12 @@
4461
4604
  let cssText = rule.cssText;
4462
4605
  let textDiffersFromPrev = false;
4463
4606
  notFoundCacheKeys.delete(cssText);
4464
- if (rule.parentRule instanceof CSSMediaRule) {
4607
+ if (isMediaRule(rule.parentRule)) {
4465
4608
  cssText += `;${rule.parentRule.media.mediaText}`;
4466
4609
  }
4610
+ if (isLayerRule(rule.parentRule)) {
4611
+ cssText += `;${rule.parentRule.name}`;
4612
+ }
4467
4613
  if (!rulesTextCache.has(cssText)) {
4468
4614
  rulesTextCache.add(cssText);
4469
4615
  textDiffersFromPrev = true;
@@ -4728,7 +4874,7 @@
4728
4874
  function buildStyleSheet() {
4729
4875
  function createTarget(group, parent) {
4730
4876
  const {rule} = group;
4731
- if (rule instanceof CSSMediaRule) {
4877
+ if (isMediaRule(rule)) {
4732
4878
  const {media} = rule;
4733
4879
  const index = parent.cssRules.length;
4734
4880
  parent.insertRule(
@@ -4737,6 +4883,12 @@
4737
4883
  );
4738
4884
  return parent.cssRules[index];
4739
4885
  }
4886
+ if (isLayerRule(rule)) {
4887
+ const {name} = rule;
4888
+ const index = parent.cssRules.length;
4889
+ parent.insertRule(`@layer ${name} {}`, index);
4890
+ return parent.cssRules[index];
4891
+ }
4740
4892
  return parent;
4741
4893
  }
4742
4894
  function iterateReadyRules(group, target, styleIterator) {
@@ -4991,9 +5143,7 @@
4991
5143
  if (!(element instanceof HTMLStyleElement)) {
4992
5144
  return false;
4993
5145
  }
4994
- const cssText = removeCSSComments$1(
4995
- element.textContent ?? ""
4996
- ).trim();
5146
+ const cssText = removeCSSComments(element.textContent ?? "").trim();
4997
5147
  return cssText.match(cssImportRegex);
4998
5148
  }
4999
5149
  function hasImports(cssRules, checkCrossOrigin) {
@@ -5367,7 +5517,7 @@
5367
5517
  });
5368
5518
  }
5369
5519
  async function replaceCSSImports(cssText, basePath, cache = new Map()) {
5370
- cssText = removeCSSComments$1(cssText);
5520
+ cssText = removeCSSComments(cssText);
5371
5521
  cssText = replaceCSSFontFace(cssText);
5372
5522
  cssText = replaceCSSRelativeURLsWithAbsolute(cssText, basePath);
5373
5523
  const importMatches = getMatches(cssImportRegex, cssText);
@@ -6589,6 +6739,7 @@
6589
6739
  const enableCustomElementRegistryProxy = !(
6590
6740
  fixes && fixes.disableCustomElementRegistryProxy
6591
6741
  );
6742
+ document.dispatchEvent(new CustomEvent("__darkreader__cleanUp"));
6592
6743
  {
6593
6744
  const proxyScript = createOrUpdateScript("darkreader--proxy");
6594
6745
  proxyScript.append(
@@ -6846,7 +6997,6 @@
6846
6997
  }
6847
6998
  changeMetaThemeColorWhenAvailable(theme);
6848
6999
  }
6849
- let pendingAdoptedVarMatch = false;
6850
7000
  function handleAdoptedStyleSheets(node) {
6851
7001
  if (isFirefox) {
6852
7002
  const fallback = getAdoptedStyleSheetFallback(node);
@@ -6864,42 +7014,9 @@
6864
7014
  sheets.forEach((s) => {
6865
7015
  variablesStore.addRulesForMatching(s.cssRules);
6866
7016
  });
7017
+ variablesStore.matchVariablesAndDependents();
6867
7018
  newManger.render(theme, ignoredImageAnalysisSelectors);
6868
- pendingAdoptedVarMatch = true;
6869
7019
  });
6870
- potentialAdoptedStyleNodes.delete(node);
6871
- } else if (!potentialAdoptedStyleNodes.has(node)) {
6872
- potentialAdoptedStyleNodes.add(node);
6873
- }
6874
- }
6875
- const potentialAdoptedStyleNodes = new Set();
6876
- let potentialAdoptedStyleFrameId = null;
6877
- function watchPotentialAdoptedStyleNodes() {
6878
- potentialAdoptedStyleFrameId = requestAnimationFrame(() => {
6879
- let changed = false;
6880
- potentialAdoptedStyleNodes.forEach((node) => {
6881
- if (node.isConnected) {
6882
- handleAdoptedStyleSheets(node);
6883
- changed = true;
6884
- } else {
6885
- potentialAdoptedStyleNodes.delete(node);
6886
- }
6887
- });
6888
- if (changed || pendingAdoptedVarMatch) {
6889
- variablesStore.matchVariablesAndDependents();
6890
- pendingAdoptedVarMatch = false;
6891
- }
6892
- watchPotentialAdoptedStyleNodes();
6893
- });
6894
- }
6895
- function stopWatchingPotentialAdoptedStyleNodes() {
6896
- potentialAdoptedStyleFrameId &&
6897
- cancelAnimationFrame(potentialAdoptedStyleFrameId);
6898
- potentialAdoptedStyleNodes.clear();
6899
- if (isFirefox) {
6900
- document.dispatchEvent(
6901
- new CustomEvent("__darkreader__stopAdoptedStyleSheetsWatcher")
6902
- );
6903
7020
  }
6904
7021
  }
6905
7022
  function getAdoptedStyleChangeToken(node) {
@@ -6971,7 +7088,6 @@
6971
7088
  handleAdoptedStyleSheets(shadowRoot);
6972
7089
  }
6973
7090
  );
6974
- watchPotentialAdoptedStyleNodes();
6975
7091
  watchForInlineStyles(
6976
7092
  (element) => {
6977
7093
  overrideInlineStyle(
@@ -7147,7 +7263,6 @@
7147
7263
  adoptedStyleManagers.splice(0);
7148
7264
  adoptedStyleFallbacks.forEach((fallback) => fallback.destroy());
7149
7265
  adoptedStyleFallbacks.clear();
7150
- stopWatchingPotentialAdoptedStyleNodes();
7151
7266
  metaObserver && metaObserver.disconnect();
7152
7267
  cleaners.forEach((clean) => clean());
7153
7268
  cleaners.splice(0);
@@ -7202,7 +7317,7 @@
7202
7317
  };
7203
7318
  rules.push(rule);
7204
7319
  }
7205
- ruleStart = brackets.end + 1;
7320
+ ruleStart = brackets.end;
7206
7321
  });
7207
7322
  return rules;
7208
7323
  }
@@ -7229,9 +7344,6 @@
7229
7344
  }
7230
7345
  return ranges;
7231
7346
  }
7232
- function removeCSSComments(cssText) {
7233
- return cssText.trim().replace(/\/\*.*?\*\//g, "");
7234
- }
7235
7347
  function getTokenExclusionRanges(cssText) {
7236
7348
  const singleQuoteGoesFirst =
7237
7349
  cssText.indexOf("'") < cssText.indexOf('"');
@@ -7287,13 +7399,19 @@
7287
7399
  );
7288
7400
  return declarations;
7289
7401
  }
7402
+ function isParsedStyleRule(rule) {
7403
+ return "selectors" in rule;
7404
+ }
7290
7405
 
7291
7406
  function formatCSS(cssText) {
7292
7407
  const parsed = parseCSS(cssText);
7408
+ return formatParsedCSS(parsed);
7409
+ }
7410
+ function formatParsedCSS(parsed) {
7293
7411
  const lines = [];
7294
7412
  const tab = " ";
7295
7413
  function formatRule(rule, indent) {
7296
- if (isStyleRule(rule)) {
7414
+ if (isParsedStyleRule(rule)) {
7297
7415
  formatStyleRule(rule, indent);
7298
7416
  } else {
7299
7417
  formatAtRule(rule, indent);
@@ -7338,13 +7456,10 @@
7338
7456
  return aNorm.localeCompare(bNorm);
7339
7457
  });
7340
7458
  }
7341
- function isStyleRule(rule) {
7342
- return "selectors" in rule;
7343
- }
7344
7459
  function clearEmptyRules(rules) {
7345
7460
  for (let i = rules.length - 1; i >= 0; i--) {
7346
7461
  const rule = rules[i];
7347
- if (isStyleRule(rule)) {
7462
+ if (isParsedStyleRule(rule)) {
7348
7463
  if (rule.declarations.length === 0) {
7349
7464
  rules.splice(i, 1);
7350
7465
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "darkreader",
3
- "version": "4.9.80",
3
+ "version": "4.9.81",
4
4
  "description": "Dark mode for every website",
5
5
  "scripts": {
6
6
  "api": "node --max-old-space-size=3072 tasks/cli.js build --api",
@@ -58,24 +58,21 @@
58
58
  "@rollup/plugin-node-resolve": "15.2.3",
59
59
  "@rollup/plugin-replace": "5.0.5",
60
60
  "@rollup/plugin-typescript": "11.1.6",
61
- "@rollup/pluginutils": "5.1.0",
62
61
  "@types/chrome": "0.0.263",
63
- "@types/eslint": "8.56.5",
62
+ "@types/eslint": "8.56.6",
64
63
  "@types/jasmine": "5.1.4",
65
64
  "@types/jest": "29.5.12",
66
65
  "@types/karma": "6.3.8",
67
66
  "@types/karma-coverage": "2.0.3",
68
- "@types/node": "20.11.25",
69
- "@types/offscreencanvas": "2019.7.3",
67
+ "@types/node": "20.12.2",
70
68
  "@types/ws": "8.5.10",
71
- "@typescript-eslint/eslint-plugin": "7.1.1",
72
- "@typescript-eslint/parser": "7.1.1",
69
+ "@typescript-eslint/eslint-plugin": "7.4.0",
70
+ "@typescript-eslint/parser": "7.4.0",
73
71
  "chokidar": "3.6.0",
74
72
  "eslint": "8.57.0",
75
73
  "eslint-plugin-compat": "4.2.0",
76
74
  "eslint-plugin-import": "2.29.1",
77
75
  "eslint-plugin-local": "4.2.1",
78
- "get-stream": "8.0.1",
79
76
  "globby": "14.0.1",
80
77
  "jasmine-core": "5.1.2",
81
78
  "jest": "29.7.0",
@@ -91,12 +88,12 @@
91
88
  "less": "4.2.0",
92
89
  "malevic": "0.20.1",
93
90
  "prettier": "3.2.5",
94
- "puppeteer-core": "22.4.1",
95
- "rollup": "4.12.1",
91
+ "puppeteer-core": "22.6.1",
92
+ "rollup": "4.13.2",
96
93
  "rollup-plugin-istanbul": "5.0.0",
97
94
  "ts-jest": "29.1.2",
98
95
  "tslib": "2.6.2",
99
- "typescript": "5.4.2",
96
+ "typescript": "5.4.3",
100
97
  "web-ext": "7.11.0",
101
98
  "ws": "8.16.0",
102
99
  "yazl": "2.5.1"