From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@salesforce.com>
Date: Thu, 6 Oct 2022 04:09:16 -0700
Subject: fix: expose the built-in electron module via the ESM loader

This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer

diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js
index eb5f0be49395b0192f18738d549241ae98793df7..522fd5cc6bea3e7fe4089eb25d64d65d2e8784ca 100644
--- a/lib/internal/modules/esm/get_format.js
+++ b/lib/internal/modules/esm/get_format.js
@@ -30,6 +30,7 @@ const protocolHandlers = {
   'http:': getHttpProtocolModuleFormat,
   'https:': getHttpProtocolModuleFormat,
   'node:'() { return 'builtin'; },
+  'electron:'() { return 'commonjs'; },
 };
 
 /**
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index fd7d2feada9bbbba589fe89230e45954fa2dd3be..3c9b1ad93f2c6b5fde5e9ed2a8bf1dc01d94a8de 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -824,6 +824,8 @@ function parsePackageName(specifier, base) {
   return { packageName, packageSubpath, isScoped };
 }
 
+const electronSpecifiers = new SafeSet(['electron', 'electron/main', 'electron/common', 'electron/renderer']);
+
 /**
  * @param {string} specifier
  * @param {string | URL | undefined} base
@@ -836,6 +838,10 @@ function packageResolve(specifier, base, conditions) {
     return new URL('node:' + specifier);
   }
 
+  if (electronSpecifiers.has(specifier)) {
+    return new URL('electron:electron');
+  }
+
   const { packageName, packageSubpath, isScoped } =
     parsePackageName(specifier, base);
 
@@ -1034,7 +1040,7 @@ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) {
 
 function throwIfUnsupportedURLProtocol(url) {
   if (url.protocol !== 'file:' && url.protocol !== 'data:' &&
-      url.protocol !== 'node:') {
+      url.protocol !== 'node:' && url.protocol !== 'electron:') {
     throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(url);
   }
 }
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index a425749e82acd7593c9fb1ceffedc119a4e416f2..1ceb89da21610c703f4a18be5888373c7feaa370 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -154,7 +154,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
 
   if (!cjsParse) await initCJSParse();
   const { module, exportNames } = cjsPreparseModuleExports(filename);
-  const namesWithDefault = exportNames.has('default') ?
+  const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ?
     [...exportNames] : ['default', ...exportNames];
 
   return new ModuleWrap(url, undefined, namesWithDefault, function() {
@@ -173,9 +173,9 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
       }
     }
 
-    for (const exportName of exportNames) {
-      if (!ObjectPrototypeHasOwnProperty(exports, exportName) ||
-          exportName === 'default')
+    for (const exportName of namesWithDefault) {
+      if (exportName === 'default' ||
+          !ObjectPrototypeHasOwnProperty(exports, exportName))
         continue;
       // We might trigger a getter -> dont fail.
       let value;
diff --git a/lib/internal/url.js b/lib/internal/url.js
index 7b2e0b4ffa6cc71b78dd1a1f64f7f491a6669383..41327e0f33828b1a3f276c9054293d89a7956e1d 100644
--- a/lib/internal/url.js
+++ b/lib/internal/url.js
@@ -1221,6 +1221,8 @@ function fileURLToPath(path) {
     path = new URL(path);
   else if (!isURLInstance(path))
     throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path);
+  if (path.protocol === 'electron:')
+    return 'electron';
   if (path.protocol !== 'file:')
     throw new ERR_INVALID_URL_SCHEME('file');
   return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
