darkreader 4.9.109 → 4.9.112

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/README.md CHANGED
@@ -181,7 +181,7 @@ For Dark Reader, the option "Run on sites with restrictions" is not shown becaus
181
181
 
182
182
  The fact that it is a Recommended extension means that it meets the "highest standards of security, functionality, and user experience". The quarantined domains are only related to extension security. Because Dark Reader is considered secure by Mozilla, that option is not shown, meaning **it will always run even on quarantined domains** (but will still obey the "restricted domains" list if it is not empty).
183
183
 
184
- Regarding quarantined domains specifically, there is this [comment from Firefox's source code:](https://searchfox.org/mozilla-central/source/toolkit/components/extensions/Extension.sys.mjs#2937-2938)
184
+ Regarding quarantined domains specifically, there is this [comment from Firefox's source code](https://searchfox.org/mozilla-central/rev/1838f847aa3bf909c3d34a94a8f0cd7e37fca086/toolkit/components/extensions/Extension.sys.mjs#3470-3471):
185
185
 
186
186
  ```
187
187
  // Privileged extensions and any extensions with a recommendation state are
package/darkreader.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dark Reader v4.9.109
2
+ * Dark Reader v4.9.112
3
3
  * https://darkreader.org/
4
4
  */
5
5
 
@@ -4026,10 +4026,7 @@
4026
4026
  };
4027
4027
  const modified = modify();
4028
4028
  if (unknownVars.size > 0) {
4029
- const isFallbackResolved = modified.match(
4030
- /^var\(.*?, ((var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\)))\)$/
4031
- );
4032
- if (isFallbackResolved) {
4029
+ if (isFallbackResolved(modified)) {
4033
4030
  return modified;
4034
4031
  }
4035
4032
  return new Promise((resolve) => {
@@ -4428,6 +4425,43 @@
4428
4425
  value.match(/^(((\d{1,3})|(var\([\-_A-Za-z0-9]+\))),?\s*?){3}$/)
4429
4426
  );
4430
4427
  }
4428
+ function isFallbackResolved(modified) {
4429
+ if (modified.startsWith("var(") && modified.endsWith(")")) {
4430
+ const hasNestedBrackets = modified.endsWith("))");
4431
+ const hasDoubleNestedBrackets = modified.endsWith(")))");
4432
+ const lastOpenBracketIndex = hasNestedBrackets
4433
+ ? modified.lastIndexOf("(")
4434
+ : -1;
4435
+ const firstOpenBracketIndex = hasDoubleNestedBrackets
4436
+ ? modified.lastIndexOf("(", lastOpenBracketIndex - 1)
4437
+ : lastOpenBracketIndex;
4438
+ const commaIndex = modified.lastIndexOf(
4439
+ ",",
4440
+ hasNestedBrackets ? firstOpenBracketIndex : modified.length
4441
+ );
4442
+ if (commaIndex < 0 || modified[commaIndex + 1] !== " ") {
4443
+ return false;
4444
+ }
4445
+ const fallback = modified.slice(
4446
+ commaIndex + 2,
4447
+ modified.length - 1
4448
+ );
4449
+ if (hasNestedBrackets) {
4450
+ return (
4451
+ fallback.startsWith("rgb(") ||
4452
+ fallback.startsWith("rgba(") ||
4453
+ fallback.startsWith("hsl(") ||
4454
+ fallback.startsWith("hsla(") ||
4455
+ fallback.startsWith("var(--darkreader-bg--") ||
4456
+ fallback.match(
4457
+ /^var\(--darkreader-background-[0-9a-z]+, #[0-9a-z]+\)$/
4458
+ )
4459
+ );
4460
+ }
4461
+ return fallback.match(/^(#[0-9a-f]+)|([a-z]+)$/i);
4462
+ }
4463
+ return false;
4464
+ }
4431
4465
  const textColorProps = [
4432
4466
  "color",
4433
4467
  "caret-color",
@@ -5131,14 +5165,38 @@
5131
5165
  return {render, destroy, commands};
5132
5166
  }
5133
5167
 
5134
- const hostsBreakingOnStylePosition = ["www.diffusioneshop.com", "zhale.me"];
5168
+ const hostsBreakingOnStylePosition = [
5169
+ "www.berlingske.dk",
5170
+ "www.bloomberg.com",
5171
+ "www.diffusioneshop.com",
5172
+ "www.weekendavisen.dk",
5173
+ "zhale.me"
5174
+ ];
5135
5175
  const mode = hostsBreakingOnStylePosition.includes(location.hostname)
5136
5176
  ? "away"
5137
5177
  : "next";
5138
5178
  function getStyleInjectionMode() {
5139
5179
  return mode;
5140
5180
  }
5181
+ const stylesWaitingForBody = new Set();
5182
+ let bodyObserver;
5141
5183
  function injectStyleAway(styleElement) {
5184
+ if (!document.body) {
5185
+ stylesWaitingForBody.add(styleElement);
5186
+ if (!bodyObserver) {
5187
+ bodyObserver = new MutationObserver(() => {
5188
+ if (document.body) {
5189
+ bodyObserver.disconnect();
5190
+ bodyObserver = null;
5191
+ stylesWaitingForBody.forEach((el) =>
5192
+ injectStyleAway(el)
5193
+ );
5194
+ stylesWaitingForBody.clear();
5195
+ }
5196
+ });
5197
+ }
5198
+ return;
5199
+ }
5142
5200
  let container = document.body.querySelector(
5143
5201
  ".darkreader-style-container"
5144
5202
  );
@@ -5148,9 +5206,32 @@
5148
5206
  container.classList.add("darkreader-style-container");
5149
5207
  container.style.display = "none";
5150
5208
  document.body.append(container);
5209
+ containerObserver = new MutationObserver(() => {
5210
+ if (container?.nextElementSibling != null) {
5211
+ container
5212
+ .querySelectorAll(".darkreader--sync")
5213
+ .forEach((el) => {
5214
+ if (el.sheet.cssRules.length > 0) {
5215
+ let cssText = "";
5216
+ for (const rule of el.sheet.cssRules) {
5217
+ cssText += rule.cssText;
5218
+ }
5219
+ el.textContent = cssText;
5220
+ }
5221
+ });
5222
+ document.body.append(container);
5223
+ }
5224
+ });
5225
+ containerObserver.observe(document.body, {childList: true});
5151
5226
  }
5152
5227
  container.append(styleElement);
5153
5228
  }
5229
+ let containerObserver;
5230
+ function removeStyleContainer() {
5231
+ bodyObserver?.disconnect();
5232
+ containerObserver?.disconnect();
5233
+ document.querySelector(".darkreader-style-container")?.remove();
5234
+ }
5154
5235
 
5155
5236
  const overrides = {
5156
5237
  "background-color": {
@@ -6292,7 +6373,8 @@
6292
6373
  force,
6293
6374
  isAsyncCancelled
6294
6375
  });
6295
- isOverrideEmpty = syncStyle.sheet.cssRules.length === 0;
6376
+ isOverrideEmpty =
6377
+ !syncStyle.sheet || syncStyle.sheet.cssRules.length === 0;
6296
6378
  if (sheetModifier.shouldRebuildStyle()) {
6297
6379
  addReadyStateCompleteListener(() => update());
6298
6380
  }
@@ -8084,6 +8166,7 @@
8084
8166
  loadingStyles.clear();
8085
8167
  cleanLoadingLinks();
8086
8168
  forEach(document.querySelectorAll(".darkreader"), removeNode);
8169
+ removeStyleContainer();
8087
8170
  adoptedStyleManagers.forEach((manager) => manager.destroy());
8088
8171
  adoptedStyleManagers.splice(0);
8089
8172
  adoptedStyleFallbacks.forEach((fallback) => fallback.destroy());
package/darkreader.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Dark Reader v4.9.109
2
+ * Dark Reader v4.9.112
3
3
  * https://darkreader.org/
4
4
  */
5
5
 
@@ -3896,10 +3896,7 @@ class VariablesStore {
3896
3896
  };
3897
3897
  const modified = modify();
3898
3898
  if (unknownVars.size > 0) {
3899
- const isFallbackResolved = modified.match(
3900
- /^var\(.*?, ((var\(--darkreader-bg--.*\))|(#[0-9A-Fa-f]+)|([a-z]+)|(rgba?\(.+\))|(hsla?\(.+\)))\)$/
3901
- );
3902
- if (isFallbackResolved) {
3899
+ if (isFallbackResolved(modified)) {
3903
3900
  return modified;
3904
3901
  }
3905
3902
  return new Promise((resolve) => {
@@ -4290,6 +4287,40 @@ function isConstructedColorVar(value) {
4290
4287
  value.match(/^(((\d{1,3})|(var\([\-_A-Za-z0-9]+\))),?\s*?){3}$/)
4291
4288
  );
4292
4289
  }
4290
+ function isFallbackResolved(modified) {
4291
+ if (modified.startsWith("var(") && modified.endsWith(")")) {
4292
+ const hasNestedBrackets = modified.endsWith("))");
4293
+ const hasDoubleNestedBrackets = modified.endsWith(")))");
4294
+ const lastOpenBracketIndex = hasNestedBrackets
4295
+ ? modified.lastIndexOf("(")
4296
+ : -1;
4297
+ const firstOpenBracketIndex = hasDoubleNestedBrackets
4298
+ ? modified.lastIndexOf("(", lastOpenBracketIndex - 1)
4299
+ : lastOpenBracketIndex;
4300
+ const commaIndex = modified.lastIndexOf(
4301
+ ",",
4302
+ hasNestedBrackets ? firstOpenBracketIndex : modified.length
4303
+ );
4304
+ if (commaIndex < 0 || modified[commaIndex + 1] !== " ") {
4305
+ return false;
4306
+ }
4307
+ const fallback = modified.slice(commaIndex + 2, modified.length - 1);
4308
+ if (hasNestedBrackets) {
4309
+ return (
4310
+ fallback.startsWith("rgb(") ||
4311
+ fallback.startsWith("rgba(") ||
4312
+ fallback.startsWith("hsl(") ||
4313
+ fallback.startsWith("hsla(") ||
4314
+ fallback.startsWith("var(--darkreader-bg--") ||
4315
+ fallback.match(
4316
+ /^var\(--darkreader-background-[0-9a-z]+, #[0-9a-z]+\)$/
4317
+ )
4318
+ );
4319
+ }
4320
+ return fallback.match(/^(#[0-9a-f]+)|([a-z]+)$/i);
4321
+ }
4322
+ return false;
4323
+ }
4293
4324
  const textColorProps = [
4294
4325
  "color",
4295
4326
  "caret-color",
@@ -4983,14 +5014,36 @@ function createAdoptedStyleSheetFallback() {
4983
5014
  return {render, destroy, commands};
4984
5015
  }
4985
5016
 
4986
- const hostsBreakingOnStylePosition = ["www.diffusioneshop.com", "zhale.me"];
5017
+ const hostsBreakingOnStylePosition = [
5018
+ "www.berlingske.dk",
5019
+ "www.bloomberg.com",
5020
+ "www.diffusioneshop.com",
5021
+ "www.weekendavisen.dk",
5022
+ "zhale.me"
5023
+ ];
4987
5024
  const mode = hostsBreakingOnStylePosition.includes(location.hostname)
4988
5025
  ? "away"
4989
5026
  : "next";
4990
5027
  function getStyleInjectionMode() {
4991
5028
  return mode;
4992
5029
  }
5030
+ const stylesWaitingForBody = new Set();
5031
+ let bodyObserver;
4993
5032
  function injectStyleAway(styleElement) {
5033
+ if (!document.body) {
5034
+ stylesWaitingForBody.add(styleElement);
5035
+ if (!bodyObserver) {
5036
+ bodyObserver = new MutationObserver(() => {
5037
+ if (document.body) {
5038
+ bodyObserver.disconnect();
5039
+ bodyObserver = null;
5040
+ stylesWaitingForBody.forEach((el) => injectStyleAway(el));
5041
+ stylesWaitingForBody.clear();
5042
+ }
5043
+ });
5044
+ }
5045
+ return;
5046
+ }
4994
5047
  let container = document.body.querySelector(".darkreader-style-container");
4995
5048
  if (!container) {
4996
5049
  container = document.createElement("div");
@@ -4998,9 +5051,32 @@ function injectStyleAway(styleElement) {
4998
5051
  container.classList.add("darkreader-style-container");
4999
5052
  container.style.display = "none";
5000
5053
  document.body.append(container);
5054
+ containerObserver = new MutationObserver(() => {
5055
+ if (container?.nextElementSibling != null) {
5056
+ container
5057
+ .querySelectorAll(".darkreader--sync")
5058
+ .forEach((el) => {
5059
+ if (el.sheet.cssRules.length > 0) {
5060
+ let cssText = "";
5061
+ for (const rule of el.sheet.cssRules) {
5062
+ cssText += rule.cssText;
5063
+ }
5064
+ el.textContent = cssText;
5065
+ }
5066
+ });
5067
+ document.body.append(container);
5068
+ }
5069
+ });
5070
+ containerObserver.observe(document.body, {childList: true});
5001
5071
  }
5002
5072
  container.append(styleElement);
5003
5073
  }
5074
+ let containerObserver;
5075
+ function removeStyleContainer() {
5076
+ bodyObserver?.disconnect();
5077
+ containerObserver?.disconnect();
5078
+ document.querySelector(".darkreader-style-container")?.remove();
5079
+ }
5004
5080
 
5005
5081
  const overrides = {
5006
5082
  "background-color": {
@@ -6096,7 +6172,8 @@ function manageStyle(element, {update, loadingStart, loadingEnd}) {
6096
6172
  force,
6097
6173
  isAsyncCancelled
6098
6174
  });
6099
- isOverrideEmpty = syncStyle.sheet.cssRules.length === 0;
6175
+ isOverrideEmpty =
6176
+ !syncStyle.sheet || syncStyle.sheet.cssRules.length === 0;
6100
6177
  if (sheetModifier.shouldRebuildStyle()) {
6101
6178
  addReadyStateCompleteListener(() => update());
6102
6179
  }
@@ -7830,6 +7907,7 @@ function removeDynamicTheme() {
7830
7907
  loadingStyles.clear();
7831
7908
  cleanLoadingLinks();
7832
7909
  forEach(document.querySelectorAll(".darkreader"), removeNode);
7910
+ removeStyleContainer();
7833
7911
  adoptedStyleManagers.forEach((manager) => manager.destroy());
7834
7912
  adoptedStyleManagers.splice(0);
7835
7913
  adoptedStyleFallbacks.forEach((fallback) => fallback.destroy());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "darkreader",
3
- "version": "4.9.109",
3
+ "version": "4.9.112",
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",
@@ -26,6 +26,7 @@
26
26
  "test:chrome-mv3": "node tasks/cli.js build --debug --test --chrome-mv3 && jest --config=tests/browser/jest.config.chrome-mv3.mjs --runInBand",
27
27
  "test:ci": "npm run test:unit",
28
28
  "test:coverage": "jest --config=tests/unit/jest.config.mjs --coverage",
29
+ "test:edge": "node tasks/cli.js build --debug --test --plus && jest --config=tests/browser/jest.config.mjs --runInBand",
29
30
  "test:firefox": "node tasks/cli.js build --debug --test --firefox-mv2 && jest --config=tests/browser/jest.config.firefox.mjs --runInBand",
30
31
  "test:inject": "node --max-old-space-size=3072 node_modules/.bin/karma start ./tests/inject/karma.conf.cjs",
31
32
  "test:inject:debug": "node --max-old-space-size=3072 node_modules/.bin/karma start ./tests/inject/karma.conf.cjs --debug",
@@ -65,28 +66,28 @@
65
66
  "malevic": "0.20.2"
66
67
  },
67
68
  "devDependencies": {
68
- "@eslint/compat": "1.3.0",
69
+ "@eslint/compat": "1.4.0",
69
70
  "@eslint/eslintrc": "3.3.1",
70
- "@eslint/js": "9.29.0",
71
- "@rollup/plugin-node-resolve": "16.0.1",
71
+ "@eslint/js": "9.37.0",
72
+ "@rollup/plugin-node-resolve": "16.0.3",
72
73
  "@rollup/plugin-replace": "6.0.2",
73
- "@rollup/plugin-typescript": "12.1.3",
74
- "@stylistic/eslint-plugin": "5.0.0",
75
- "@types/chrome": "0.0.326",
74
+ "@rollup/plugin-typescript": "12.1.4",
75
+ "@stylistic/eslint-plugin": "5.4.0",
76
+ "@types/chrome": "0.1.24",
76
77
  "@types/eslint": "9.6.1",
77
- "@types/jasmine": "5.1.8",
78
+ "@types/jasmine": "5.1.10",
78
79
  "@types/jest": "30.0.0",
79
80
  "@types/karma": "6.3.9",
80
81
  "@types/karma-coverage": "2.0.3",
81
- "@types/node": "24.0.3",
82
+ "@types/node": "24.7.2",
82
83
  "@types/ws": "8.18.1",
83
84
  "chokidar": "4.0.3",
84
85
  "eslint-plugin-compat": "6.0.2",
85
86
  "eslint-plugin-import": "2.32.0",
86
- "globals": "16.2.0",
87
- "globby": "14.1.0",
88
- "jasmine-core": "5.8.0",
89
- "jest": "30.0.2",
87
+ "globals": "16.4.0",
88
+ "globby": "15.0.0",
89
+ "jasmine-core": "5.12.0",
90
+ "jest": "30.2.0",
90
91
  "jest-extended": "6.0.0",
91
92
  "karma": "6.4.4",
92
93
  "karma-chrome-launcher": "3.2.0",
@@ -96,20 +97,20 @@
96
97
  "karma-rollup-preprocessor": "7.0.8",
97
98
  "karma-safari-launcher": "1.0.0",
98
99
  "karma-spec-reporter": "0.0.36",
99
- "less": "4.3.0",
100
- "prettier": "3.6.0",
101
- "puppeteer-core": "24.10.2",
102
- "rollup": "4.44.0",
100
+ "less": "4.4.2",
101
+ "prettier": "3.6.2",
102
+ "puppeteer-core": "24.24.1",
103
+ "rollup": "4.52.4",
103
104
  "rollup-plugin-istanbul": "5.0.0",
104
- "ts-jest": "29.4.0",
105
+ "ts-jest": "29.4.5",
105
106
  "tslib": "2.8.1",
106
- "typescript": "5.8.3",
107
- "typescript-eslint": "8.35.0",
108
- "ws": "8.18.2",
107
+ "typescript": "5.9.3",
108
+ "typescript-eslint": "8.46.1",
109
+ "ws": "8.18.3",
109
110
  "yazl": "3.3.1"
110
111
  },
111
112
  "optionalDependencies": {
112
- "@rollup/rollup-linux-x64-gnu": "4.44.0",
113
- "@rollup/rollup-win32-x64-msvc": "4.44.0"
113
+ "@rollup/rollup-linux-x64-gnu": "4.52.4",
114
+ "@rollup/rollup-win32-x64-msvc": "4.52.4"
114
115
  }
115
116
  }