Selaa lähdekoodia

feat: show script name in syntax errors during injection

tophf 5 vuotta sitten
vanhempi
sitoutus
753d5eea9a
1 muutettua tiedostoa jossa 25 lisäystä ja 7 poistoa
  1. 25 7
      src/injected/content/inject.js

+ 25 - 7
src/injected/content/inject.js

@@ -11,6 +11,8 @@ import { defineProperty, describeProperty, forEachEntry, objectPick } from '#/co
 import {
   forEach, push,
   append, createElementNS, remove, NS_HTML,
+  addEventListener, removeEventListener,
+  log,
 } from '../utils/helpers';
 import bridge from './bridge';
 
@@ -26,11 +28,12 @@ const { get: getHead } = describeProperty(Document.prototype, 'head')
   || describeProperty(HTMLDocument.prototype, 'head'); // old FF before 61;
 const { get: getDocElem } = describeProperty(Document.prototype, 'documentElement');
 const { appendChild } = Document.prototype; // same as Node.appendChild
+const stringIncludes = String.prototype.includes;
 
 bridge.addHandlers({
   // FF bug workaround to enable processing of sourceURL in injected page scripts
   InjectList(runAt) {
-    bridge.realms[INJECT_PAGE].lists[runAt]::forEach(item => inject(item.code));
+    bridge.realms[INJECT_PAGE].lists[runAt]::forEach(inject);
   },
 });
 
@@ -42,9 +45,11 @@ export function appendToRoot(node) {
 }
 
 export function injectPageSandbox(contentId, webId) {
-  inject(`(${VMInitInjection}())('${webId}','${contentId}')\n//# sourceURL=${
-    browser.runtime.getURL('sandbox/injected-web.js')
-  }`);
+  inject({
+    code: `(${VMInitInjection}())('${webId}','${contentId}')\n//# sourceURL=${
+      browser.runtime.getURL('sandbox/injected-web.js')
+    }`,
+  });
 }
 
 export function injectScripts(contentId, webId, data, isXml) {
@@ -117,12 +122,25 @@ function checkInjectable() {
   return res;
 }
 
-function inject(code) {
+function inject(item) {
   const script = document::createElementNS(NS_HTML, 'script');
+  // Firefox ignores sourceURL comment when a syntax error occurs so we'll print the name manually
+  let onError;
+  if (bridge.isFirefox) {
+    onError = e => {
+      const { stack } = e.error;
+      if (typeof stack === 'string' && stack::stringIncludes(browser.runtime.getURL('/sandbox'))) {
+        log('error', [item.meta.name], e.error);
+        e.preventDefault();
+      }
+    };
+    window::addEventListener('error', onError);
+  }
   // using a safe call to an existing method so we don't have to extract textContent setter
-  script::append(code);
+  script::append(item.code);
   // When using declarativeContent there's no documentElement so we'll append to `document`
   if (!appendToRoot(script)) document::appendChild(script);
+  if (onError) window::removeEventListener('error', onError);
   script::remove();
 }
 
@@ -136,7 +154,7 @@ function injectAll(realms, runAt) {
         realmData.info = undefined;
         items::forEach(item => {
           // FF bug workaround to enable processing of sourceURL in injected page scripts
-          if (isPage && !bridge.isFirefox) inject(item.code);
+          if (isPage && !bridge.isFirefox) inject(item);
           item.code = '';
         });
       }