chore: lint code blocks in docs with ESLint (#42113)

This commit is contained in:
David Sanders 2025-05-29 12:45:26 -07:00 committed by GitHub
commit 0d70389ccb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 308 additions and 34 deletions

35
docs/.eslintrc.json Normal file
View file

@ -0,0 +1,35 @@
{
"extends": "standard",
"plugins": [
"markdown",
"unicorn"
],
"overrides": [
{
"files": ["*.md", "**/*.md"],
"processor": "markdown/markdown"
}
],
"rules": {
"@typescript-eslint/no-unused-vars": "off",
"import/order": ["error", {
"alphabetize": {
"order": "asc"
},
"newlines-between": "always",
"pathGroups": [
{
"pattern": "{electron,electron/**}",
"group": "builtin",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": []
}],
"n/no-callback-literal": "off",
"no-undef": "off",
"no-unused-expressions": "off",
"no-unused-vars": "off",
"unicorn/prefer-node-protocol": "error"
}
}

View file

@ -9,6 +9,7 @@ closed:
```js
const { app } = require('electron')
app.on('window-all-closed', () => {
app.quit()
})
@ -1023,6 +1024,7 @@ starts:
```js
const { app, BrowserWindow } = require('electron')
let myWindow = null
const additionalData = { myKey: 'myValue' }
@ -1226,6 +1228,8 @@ For `infoType` equal to `complete`:
For `infoType` equal to `basic`:
Promise is fulfilled with `Object` containing fewer attributes than when requested with `complete`. Here's an example of basic response:
<!-- eslint-skip -->
```js
{
auxAttributes:
@ -1339,6 +1343,7 @@ latest version.
``` js
const { app } = require('electron')
const path = require('node:path')
const appFolder = path.dirname(process.execPath)
@ -1413,6 +1418,7 @@ Returns `Function` - This function **must** be called once you have finished acc
```js
const { app, dialog } = require('electron')
const fs = require('node:fs')
let filepath

View file

@ -294,6 +294,7 @@ e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`.
```js
const { BaseWindow } = require('electron')
const win = new BaseWindow()
win.on('app-command', (e, cmd) => {
// Navigate the window back when the user hits their mouse back button
@ -502,6 +503,7 @@ A `boolean` property that determines whether the window is excluded from the app
```js @ts-expect-error=[12]
const { Menu, BaseWindow } = require('electron')
const win = new BaseWindow({ height: 600, width: 600 })
const template = [
@ -727,6 +729,7 @@ Resizes and moves the window to the supplied bounds. Any properties that are not
```js
const { BaseWindow } = require('electron')
const win = new BaseWindow()
// set all bounds properties
@ -987,6 +990,7 @@ a HTML-rendered toolbar. For example:
```js
const { BaseWindow } = require('electron')
const win = new BaseWindow()
const toolbarRect = document.getElementById('toolbar').getBoundingClientRect()

View file

@ -40,6 +40,7 @@ the window after this event will have no visual flash:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
win.show()
@ -373,6 +374,7 @@ e.g. `APPCOMMAND_BROWSER_BACKWARD` is emitted as `browser-backward`.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.on('app-command', (e, cmd) => {
// Navigate the window back when the user hits their mouse back button
@ -820,6 +822,7 @@ Resizes and moves the window to the supplied bounds. Any properties that are not
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
// set all bounds properties
@ -1080,6 +1083,7 @@ a HTML-rendered toolbar. For example:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
const toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
@ -1232,9 +1236,10 @@ method:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
const url = require('url').format({
const url = require('node:url').format({
protocol: 'file',
slashes: true,
pathname: require('node:path').join(__dirname, 'index.html')
@ -1248,6 +1253,7 @@ the following:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.loadURL('http://localhost:8000/post', {

View file

@ -8,6 +8,7 @@ is emitted:
```js
const { app } = require('electron')
app.commandLine.appendSwitch('remote-debugging-port', '8315')
app.commandLine.appendSwitch('host-rules', 'MAP * 127.0.0.1')
@ -188,6 +189,7 @@ For example:
```js
const { app } = require('electron')
app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')
```

View file

@ -9,6 +9,7 @@ The following example shows how to check if the `--disable-gpu` flag is set.
```js
const { app } = require('electron')
app.commandLine.hasSwitch('disable-gpu')
```

View file

@ -189,7 +189,9 @@ Be very cautious about which globals and APIs you expose to untrusted remote con
```js
const { contextBridge } = require('electron')
const crypto = require('node:crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')

View file

@ -10,6 +10,7 @@ runtime that allows interacting with pages and instrumenting them.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
try {

View file

@ -8,6 +8,7 @@ An example of showing a dialog to select multiple files:
```js
const { dialog } = require('electron')
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
```
@ -52,6 +53,8 @@ The `window` argument allows the dialog to attach itself to a parent window, mak
The `filters` specifies an array of file types that can be displayed or
selected when you want to limit the user to a specific type. For example:
<!-- eslint-skip -->
```js
{
filters: [
@ -126,6 +129,8 @@ The `window` argument allows the dialog to attach itself to a parent window, mak
The `filters` specifies an array of file types that can be displayed or
selected when you want to limit the user to a specific type. For example:
<!-- eslint-skip -->
```js
{
filters: [

View file

@ -9,6 +9,7 @@ The following example shows how to bounce your icon on the dock.
```js
const { app } = require('electron')
app.dock?.bounce()
```

View file

@ -12,6 +12,7 @@ control the download item.
```js
// In the main process.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.webContents.session.on('will-download', (event, item, webContents) => {
// Set the save path, making Electron not to prompt a save dialog.

View file

@ -77,6 +77,7 @@ extension to be loaded.
```js
const { app, session } = require('electron')
const path = require('node:path')
app.whenReady().then(async () => {

View file

@ -15,9 +15,12 @@ Process: [Main](../glossary.md#main-process)
Example:
<!-- eslint-disable import/order -->
```js
// Main process
const { BrowserWindow, MessageChannelMain } = require('electron')
const w = new BrowserWindow()
const { port1, port2 } = new MessageChannelMain()
w.webContents.postMessage('port', null, [port2])
@ -25,6 +28,7 @@ port1.postMessage({ some: 'message' })
// Renderer process
const { ipcRenderer } = require('electron')
ipcRenderer.on('port', (e) => {
// e.ports is a list of ports sent along with this message
e.ports[0].onmessage = (messageEvent) => {

View file

@ -86,6 +86,7 @@ images/
```js title='Main Process'
const { Tray } = require('electron')
const appTray = new Tray('/Users/somebody/images/icon.png')
```

View file

@ -28,6 +28,7 @@ Example usage:
```js
const { app } = require('electron')
app.whenReady().then(() => {
const { net } = require('electron')
const request = net.request('https://github.com')

View file

@ -9,6 +9,7 @@ An example of implementing a protocol that has the same effect as the
```js
const { app, protocol, net } = require('electron')
const path = require('node:path')
const url = require('node:url')
@ -38,8 +39,9 @@ to register it to that session explicitly.
```js
const { app, BrowserWindow, net, protocol, session } = require('electron')
const path = require('node:path')
const url = require('url')
const url = require('node:url')
app.whenReady().then(() => {
const partition = 'persist:example'
@ -76,6 +78,7 @@ Policy:
```js
const { protocol } = require('electron')
protocol.registerSchemesAsPrivileged([
{ scheme: 'foo', privileges: { bypassCSP: true } }
])
@ -128,8 +131,9 @@ Example:
```js
const { app, net, protocol } = require('electron')
const path = require('node:path')
const { pathToFileURL } = require('url')
const { pathToFileURL } = require('node:url')
protocol.registerSchemesAsPrivileged([
{
@ -330,7 +334,8 @@ Example:
```js
const { protocol } = require('electron')
const { PassThrough } = require('stream')
const { PassThrough } = require('node:stream')
function createStream (text) {
const rv = new PassThrough() // PassThrough is also a Readable stream

View file

@ -109,6 +109,7 @@ Starts the service worker or does nothing if already running.
```js
const { app, session } = require('electron')
const { serviceWorkers } = session.defaultSession
// Collect service workers scopes

View file

@ -79,6 +79,7 @@ You can create a `Session` object in the `session` module:
```js
const { session } = require('electron')
const ses = session.fromPartition('persist:name')
console.log(ses.getUserAgent())
```
@ -100,8 +101,9 @@ Emitted when Electron is about to download `item` in `webContents`.
Calling `event.preventDefault()` will cancel the download and `item` will not be
available from next tick of the process.
```js @ts-expect-error=[4]
```js @ts-expect-error=[5]
const { session } = require('electron')
session.defaultSession.on('will-download', (event, item, webContents) => {
event.preventDefault()
require('got')(item.getURL()).then((response) => {
@ -852,6 +854,7 @@ verify proc.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.webContents.session.setCertificateVerifyProc((request, callback) => {
@ -903,6 +906,7 @@ Most web APIs do a permission check and then make a permission request if the ch
```js
const { session } = require('electron')
session.fromPartition('some-partition').setPermissionRequestHandler((webContents, permission, callback) => {
if (webContents.getURL() === 'some-host' && permission === 'notifications') {
return callback(false) // denied.
@ -952,7 +956,9 @@ To clear the handler, call `setPermissionCheckHandler(null)`.
```js
const { session } = require('electron')
const url = require('url')
const url = require('node:url')
session.fromPartition('some-partition').setPermissionCheckHandler((webContents, permission, requestingOrigin) => {
if (new URL(requestingOrigin).hostname === 'some-host' && permission === 'notifications') {
return true // granted
@ -1189,6 +1195,7 @@ automatically. To clear the handler, call `setBluetoothPairingHandler(null)`.
```js
const { app, BrowserWindow, session } = require('electron')
const path = require('node:path')
function createWindow () {
@ -1518,6 +1525,7 @@ extension to be loaded.
```js
const { app, session } = require('electron')
const path = require('node:path')
app.whenReady().then(async () => {
@ -1659,6 +1667,7 @@ A [`Protocol`](protocol.md) object for this session.
```js
const { app, session } = require('electron')
const path = require('node:path')
app.whenReady().then(() => {

View file

@ -12,6 +12,8 @@ The number represented by `status` means different things on different platforms
Below is an example of some of the additional options that may be set which
may be different on each platform.
<!-- eslint-skip -->
```js
{
name: 'Austin_4th_Floor_Printer___C02XK13BJHD4',

View file

@ -26,6 +26,8 @@
An example TraceConfig that roughly matches what Chrome DevTools records:
<!-- eslint-skip -->
```js
{
recording_mode: 'record-until-full',

View file

@ -6,6 +6,7 @@ Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-p
```js
const { systemPreferences } = require('electron')
console.log(systemPreferences.getEffectiveAppearance())
```

View file

@ -9,6 +9,7 @@ module is emitted.
```js
const { BaseWindow, View } = require('electron')
const win = new BaseWindow()
const view = new View()

View file

@ -9,6 +9,7 @@ module is emitted.
```js
const { BaseWindow, WebContentsView } = require('electron')
const win = new BaseWindow({ width: 800, height: 400 })
const view1 = new WebContentsView()
@ -52,6 +53,7 @@ Use this to interact with the `WebContents`, for instance to load a URL.
```js
const { WebContentsView } = require('electron')
const view = new WebContentsView()
view.webContents.loadURL('https://electronjs.org/')
```

View file

@ -55,6 +55,7 @@ These methods can be accessed from the `webContents` module:
```js
const { webContents } = require('electron')
console.log(webContents)
```
@ -446,6 +447,7 @@ and allow the page to be unloaded.
```js
const { BrowserWindow, dialog } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
win.webContents.on('will-prevent-unload', (event) => {
const choice = dialog.showMessageBoxSync(win, {
@ -1103,6 +1105,7 @@ Returns `string` - The URL of the current web page.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('https://github.com').then(() => {
const currentURL = win.webContents.getURL()
@ -1772,9 +1775,10 @@ An example of `webContents.printToPDF`:
```js
const { app, BrowserWindow } = require('electron')
const fs = require('node:fs')
const path = require('node:path')
const os = require('node:os')
const path = require('node:path')
app.whenReady().then(() => {
const win = new BrowserWindow()
@ -1806,6 +1810,7 @@ creation:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.webContents.on('devtools-opened', () => {
win.webContents.addWorkSpace(__dirname)
@ -1872,6 +1877,7 @@ An example of showing devtools in a `<webview>` tag:
```js
// Main process
const { ipcMain, webContents } = require('electron')
ipcMain.on('open-devtools', (event, targetContentsId, devtoolsContentsId) => {
const target = webContents.fromId(targetContentsId)
const devtools = webContents.fromId(devtoolsContentsId)
@ -2131,6 +2137,7 @@ Returns `Promise<void>` - resolves if the page is saved.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.loadURL('https://github.com')

View file

@ -99,9 +99,11 @@ with an array of misspelt words when complete.
An example of using [node-spellchecker][spellchecker] as provider:
```js @ts-expect-error=[2,6]
```js @ts-expect-error=[3,8]
const { webFrame } = require('electron')
const spellChecker = require('spellchecker')
webFrame.setSpellCheckProvider('en-US', {
spellCheck (words, callback) {
setTimeout(() => {
@ -212,11 +214,14 @@ caches.
```js
const { webFrame } = require('electron')
console.log(webFrame.getResourceUsage())
```
This will generate:
<!-- eslint-skip -->
```js
{
images: {

View file

@ -22,5 +22,6 @@ const oldPath = document.querySelector('input').files[0].path
// After
const { webUtils } = require('electron')
const newPath = webUtils.getPathForFile(document.querySelector('input').files[0])
```

View file

@ -987,6 +987,7 @@ webview.send('ping')
```js
// In guest page.
const { ipcRenderer } = require('electron')
ipcRenderer.on('ping', () => {
ipcRenderer.sendToHost('pong')
})

View file

@ -165,8 +165,10 @@ An example of the contents of this file can be found [here](https://github.com/e
Add your module to the module list found at `"lib/browser/api/module-list.ts"` like so:
<!-- eslint-disable semi -->
```ts title='lib/browser/api/module-list.ts' @ts-nocheck
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'apiName', loader: () => require('./api-name') },
{ name: 'apiName', loader: () => require('./api-name') }
];
```

View file

@ -67,6 +67,7 @@ code from this:
```js
const { app, Tray } = require('electron')
app.whenReady().then(() => {
const tray = new Tray('/path/to/icon.png')
tray.setTitle('hello world')
@ -77,6 +78,7 @@ to this:
```js
const { app, Tray } = require('electron')
let tray = null
app.whenReady().then(() => {
tray = new Tray('/path/to/icon.png')
@ -95,6 +97,7 @@ To solve this, you can turn off node integration in Electron:
```js
// In the main process.
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: false
@ -143,6 +146,7 @@ To achieve this goal, set the background in the constructor for [BrowserWindow][
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
backgroundColor: '#fff'
})

View file

@ -42,6 +42,7 @@ Read a file in the ASAR archive:
```js
const fs = require('node:fs')
fs.readFileSync('/path/to/example.asar/file.txt')
```
@ -49,6 +50,7 @@ List all files under the root of the archive:
```js
const fs = require('node:fs')
fs.readdirSync('/path/to/example.asar')
```
@ -62,6 +64,7 @@ You can also display a web page in an ASAR archive with `BrowserWindow`:
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.loadURL('file:///path/to/example.asar/static/index.html')
@ -91,6 +94,7 @@ content of an ASAR archive as a file. For this purpose you can use the built-in
```js
const originalFs = require('original-fs')
originalFs.readFileSync('/path/to/example.asar')
```
@ -99,6 +103,7 @@ the `fs` module:
```js
const fs = require('node:fs')
process.noAsar = true
fs.readFileSync('/path/to/example.asar')
```

View file

@ -95,6 +95,7 @@ or to retrieve other Electron process information:
```js @ts-nocheck
import fs from 'node:fs'
import path from 'node:path'
import { browser, expect } from '@wdio/globals'
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), { encoding: 'utf-8' }))
@ -165,6 +166,7 @@ ChromeDriver and where to find the binary of your Electron app:
```js title='test.js' @ts-expect-error=[1]
const webdriver = require('selenium-webdriver')
const driver = new webdriver.Builder()
// The "9515" is the port opened by ChromeDriver.
.usingServer('http://localhost:9515')
@ -317,9 +319,10 @@ To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.o
The test suite will spawn the Electron process, then establish a simple messaging protocol:
```js title='testDriver.js' @ts-nocheck
const childProcess = require('node:child_process')
const electronPath = require('electron')
const childProcess = require('node:child_process')
// spawn the process
const env = { /* ... */ }
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
@ -436,8 +439,10 @@ framework of your choosing. The following example uses
or Mocha would work as well:
```js title='test.js' @ts-nocheck
const test = require('ava')
const electronPath = require('electron')
const test = require('ava')
const { TestDriver } = require('./testDriver')
const app = new TestDriver({

View file

@ -76,6 +76,7 @@ use the native UI to control the window.
```js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover' })
```
@ -89,6 +90,7 @@ by a fixed amount.
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ titleBarStyle: 'hiddenInset' })
```
@ -98,6 +100,7 @@ constructor.
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
trafficLightPosition: { x: 10, y: 10 }
@ -112,6 +115,7 @@ on the value of its boolean parameter.
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
// hides the traffic lights
win.setWindowButtonVisibility(false)
@ -149,6 +153,7 @@ default to the standard system height:
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
titleBarStyle: 'hidden',
titleBarOverlay: {

View file

@ -62,6 +62,7 @@ API:
```js title='main.js'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.setIgnoreMouseEvents(true)
```
@ -75,6 +76,7 @@ allowing events such as `mouseleave` to be emitted:
```js title='main.js'
const { BrowserWindow, ipcMain } = require('electron')
const path = require('node:path')
const win = new BrowserWindow({

View file

@ -135,6 +135,7 @@ Finally, the `main.js` file represents the main process and contains the actual
```js
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
const path = require('node:path')
const createWindow = () => {

View file

@ -35,8 +35,9 @@ Using the [React Developer Tools][react-devtools] as an example:
```js
const { app, session } = require('electron')
const path = require('node:path')
const os = require('node:os')
const path = require('node:path')
// on macOS
const reactDevToolsPath = path.join(

View file

@ -85,6 +85,8 @@ The `@babel/plugin-transform-modules-commonjs` plugin will transform
ESM imports down to `require` calls. The exact syntax will depend on the
[`importInterop` setting](https://babeljs.io/docs/babel-plugin-transform-modules-commonjs#importinterop).
<!-- eslint-skip -->
```js @nolint @ts-nocheck title='@babel/plugin-transform-modules-commonjs'
import foo from "foo";
import { bar } from "bar";

View file

@ -37,6 +37,7 @@ Here is an example that shows how to use In-App Purchases in Electron. You'll ha
```js
// Main process
const { inAppPurchase } = require('electron')
const PRODUCT_IDS = ['id1', 'id2']
// Listen for transactions as soon as possible.

View file

@ -52,6 +52,7 @@ In the main process, set an IPC listener on the `set-title` channel with the `ip
```js {6-10,22} title='main.js (Main Process)'
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('node:path')
// ...
@ -183,6 +184,7 @@ provided to the renderer process. Please refer to
```js {6-13,25} title='main.js (Main Process)'
const { app, BrowserWindow, dialog, ipcMain } = require('electron')
const path = require('node:path')
// ...
@ -334,6 +336,7 @@ response.
```js title='main.js (Main Process)'
const { ipcMain } = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping" in the Node console
event.returnValue = 'pong'
@ -378,6 +381,7 @@ target renderer.
```js {11-26} title='main.js (Main Process)'
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
const path = require('node:path')
function createWindow () {
@ -412,6 +416,8 @@ function createWindow () {
For the purposes of the tutorial, it's important to note that the `click` handler
sends a message (either `1` or `-1`) to the renderer process through the `update-counter` channel.
<!-- eslint-skip -->
```js @ts-type={mainWindow:Electron.BrowserWindow}
click: () => mainWindow.webContents.send('update-counter', -1)
```

View file

@ -27,6 +27,7 @@ control our application lifecycle and create a native browser window.
```js
const { app, BrowserWindow, shell } = require('electron')
const path = require('node:path')
```

View file

@ -303,6 +303,7 @@ without having to step through the isolated world.
```js title='main.js (Main Process)'
const { BrowserWindow, app, MessageChannelMain } = require('electron')
const path = require('node:path')
app.whenReady().then(async () => {

View file

@ -1075,7 +1075,7 @@ NODE_API_MODULE(objc_addon, Init)
You're so close! We now have working Objective-C and thread-safe ways to expose methods and events to JavaScript. In this final step, let's create a JavaScript wrapper in `js/index.js` to provide a more friendly API:
```js title='js/index.js' @ts-expect-error=[10]
const EventEmitter = require('events')
const EventEmitter = require('node:events')
class ObjcMacosAddon extends EventEmitter {
constructor () {

View file

@ -269,8 +269,10 @@ Let's break down this code:
Now, let's create a JavaScript wrapper to make the addon easier to use. Create `js/index.js`:
<!-- eslint-disable import/newline-after-import,import/order -->
```js title='js/index.js' @ts-expect-error=[5]
const EventEmitter = require('events')
const EventEmitter = require('node:events')
// Load the native addon using the 'bindings' module
// This will look for the compiled .node file in various places
@ -362,6 +364,7 @@ To use this addon in an Electron application, you would:
```js @ts-expect-error=[2]
// In your main process
const myAddon = require('my-native-addon')
console.log(myAddon.helloWorld('Electron'))
```

View file

@ -74,7 +74,6 @@ if (navigationHistory.canGoToOffset(2)) {
A common flow is that you want to restore the history of a webContents - for instance to implement an "undo close tab" feature. To do so, you can call `navigationHistory.restore({ index, entries })`. This will restore the webContent's navigation history and the webContents location in said history, meaning that `goBack()` and `goForward()` navigate you through the stack as expected.
```js @ts-type={navigationHistory:Electron.NavigationHistory}
const firstWindow = new BrowserWindow()
// Later, you want a second window to have the same history and navigation position

View file

@ -175,6 +175,7 @@ you might write code that eagerly loads dependencies:
```js title='parser.js' @ts-expect-error=[2]
const fs = require('node:fs')
const fooParser = require('foo-parser')
class Parser {

View file

@ -242,8 +242,8 @@ These aliases have no impact on runtime, but can be used for typechecking
and autocomplete.
```js title="Usage example"
const { app } = require('electron/main')
const { shell } = require('electron/common')
const { app } = require('electron/main')
```
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window

View file

@ -281,7 +281,8 @@ security-conscious developers might want to assume the very opposite.
```js title='main.js (Main Process)'
const { session } = require('electron')
const { URL } = require('url')
const { URL } = require('node:url')
session
.fromPartition('some-partition')
@ -611,9 +612,10 @@ sometimes be fooled - a `startsWith('https://example.com')` test would let
`https://example.com.attacker.com` through.
```js title='main.js (Main Process)'
const { URL } = require('url')
const { app } = require('electron')
const { URL } = require('node:url')
app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const parsedUrl = new URL(navigationUrl)
@ -690,12 +692,14 @@ leveraged to execute arbitrary commands.
```js title='main.js (Main Process)' @ts-type={USER_CONTROLLED_DATA_HERE:string}
// Bad
const { shell } = require('electron')
shell.openExternal(USER_CONTROLLED_DATA_HERE)
```
```js title='main.js (Main Process)'
// Good
const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')
```

View file

@ -83,6 +83,7 @@ To attach this script to your renderer process, pass its path to the
```js {2,8-10} title="main.js"
const { app, BrowserWindow } = require('electron')
const path = require('node:path')
const createWindow = () => {
@ -204,6 +205,7 @@ you send out the `invoke` call from the renderer.
```js {1,15} title="main.js"
const { app, BrowserWindow, ipcMain } = require('electron/main')
const path = require('node:path')
const createWindow = () => {

View file

@ -126,6 +126,7 @@ following lines:
```js
const { BrowserWindow, nativeImage } = require('electron')
const path = require('node:path')
const win = new BrowserWindow()

View file

@ -29,6 +29,7 @@
"eslint": "^8.57.1",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.30.0",
"eslint-plugin-markdown": "^5.1.0",
"eslint-plugin-mocha": "^10.5.0",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-node": "^11.1.0",

View file

@ -73,6 +73,24 @@ function spawnAndCheckExitCode (cmd, args, opts) {
}
}
async function runEslint (eslint, filenames, { fix, verbose }) {
const formatter = await eslint.loadFormatter();
let successCount = 0;
const results = await eslint.lintFiles(filenames);
for (const result of results) {
successCount += result.errorCount === 0 ? 1 : 0;
if (verbose && result.errorCount === 0 && result.warningCount === 0) {
console.log(`${result.filePath}: no errors or warnings`);
}
}
console.log(formatter.format(results));
if (fix) {
await ESLint.outputFixes(results);
}
return successCount === filenames.length;
}
function cpplint (args) {
args.unshift(`--root=${SOURCE_ROOT}`);
const cmd = IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py';
@ -146,20 +164,8 @@ const LINTERS = [{
fix: opts.fix,
resolvePluginsRelativeTo: ELECTRON_ROOT
});
const formatter = await eslint.loadFormatter();
let successCount = 0;
const results = await eslint.lintFiles(filenames);
for (const result of results) {
successCount += result.errorCount === 0 ? 1 : 0;
if (opts.verbose && result.errorCount === 0 && result.warningCount === 0) {
console.log(`${result.filePath}: no errors or warnings`);
}
}
console.log(formatter.format(results));
if (opts.fix) {
await ESLint.outputFixes(results);
}
if (successCount !== filenames.length) {
const clean = await runEslint(eslint, filenames, { fix: opts.fix, verbose: opts.verbose });
if (!clean) {
console.error('Linting had errors');
process.exit(1);
}
@ -363,6 +369,26 @@ const LINTERS = [{
}
}
const eslint = new ESLint({
// Do not use the lint cache on CI builds
cache: !process.env.CI,
cacheLocation: `node_modules/.eslintcache.${crypto.createHash('md5').update(fs.readFileSync(__filename)).digest('hex')}`,
fix: opts.fix,
overrideConfigFile: path.join(ELECTRON_ROOT, 'docs', '.eslintrc.json'),
resolvePluginsRelativeTo: ELECTRON_ROOT
});
const clean = await runEslint(
eslint,
docs.filter(
// TODO(dsanders11): Once we move to newer ESLint and the flat config,
// switch to using `ignorePatterns` and `warnIgnore: false` instead of
// explicitly filtering out this file that we don't want to lint
(filename) => !filename.endsWith('docs/breaking-changes.md')
),
{ fix: opts.fix, verbose: opts.verbose }
);
errors ||= !clean;
if (errors) {
process.exit(1);
}

View file

@ -953,6 +953,13 @@
"@types/linkify-it" "^5"
"@types/mdurl" "^2"
"@types/mdast@^3.0.0":
version "3.0.15"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5"
integrity sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==
dependencies:
"@types/unist" "^2"
"@types/mdast@^4.0.0":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6"
@ -1065,6 +1072,11 @@
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
"@types/unist@^2":
version "2.0.11"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4"
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
"@types/unist@^2.0.2":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
@ -1856,16 +1868,31 @@ chalk@^5.0.0, chalk@^5.3.0:
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
character-entities-legacy@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
character-entities-legacy@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b"
integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==
character-entities@^1.0.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b"
integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==
character-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.0.tgz#508355fcc8c73893e0909efc1a44d28da2b6fdf3"
integrity sha512-oHqMj3eAuJ77/P5PaIRcqk+C3hdfNwyCD2DAUcD5gyXkegAuF2USC40CEqPscDk4I8FRGMTojGJQkXDsN5QlJA==
character-reference-invalid@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
character-reference-invalid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.0.tgz#a0bdeb89c051fe7ed5d3158b2f06af06984f2813"
@ -2650,6 +2677,13 @@ eslint-plugin-import@^2.30.0:
semver "^6.3.1"
tsconfig-paths "^3.15.0"
eslint-plugin-markdown@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-5.1.0.tgz#e87724118e822cdfc89cbf1edb40248a3bc9aece"
integrity sha512-SJeyKko1K6GwI0AN6xeCDToXDkfKZfXcexA6B+O2Wr2btUS9GrC+YgwSyVli5DJnctUHjFXcQ2cqTaAmVoLi2A==
dependencies:
mdast-util-from-markdown "^0.8.5"
eslint-plugin-mocha@^10.5.0:
version "10.5.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.5.0.tgz#0aca8d709e7cddef566e0dc252f6b02e307a2b7e"
@ -3649,11 +3683,24 @@ interpret@^3.1.1:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
is-alphabetical@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==
is-alphabetical@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.0.tgz#ef6e2caea57c63450fffc7abb6cbdafc5eb96e96"
integrity sha512-5OV8Toyq3oh4eq6sbWTYzlGdnMT/DPI5I0zxUBxjiigQsZycpkKF3kskkao3JyYGuYDHvhgJF+DrjMQp9SX86w==
is-alphanumerical@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf"
integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==
dependencies:
is-alphabetical "^1.0.0"
is-decimal "^1.0.0"
is-alphanumerical@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.0.tgz#0fbfeb6a72d21d91143b3d182bf6cf5909ee66f6"
@ -3760,6 +3807,11 @@ is-date-object@^1.0.1:
dependencies:
has-tostringtag "^1.0.0"
is-decimal@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
is-decimal@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.0.tgz#db1140337809fd043a056ae40a9bd1cdc563034c"
@ -3794,6 +3846,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
is-hexadecimal@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
is-hexadecimal@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.0.tgz#8e1ec9f48fe3eabd90161109856a23e0907a65d5"
@ -4418,6 +4475,17 @@ mdast-comment-marker@^1.0.0:
resolved "https://registry.yarnpkg.com/mdast-comment-marker/-/mdast-comment-marker-1.1.1.tgz#9c9c18e1ed57feafc1965d92b028f37c3c8da70d"
integrity sha512-TWZDaUtPLwKX1pzDIY48MkSUQRDwX/HqbTB4m3iYdL/zosi/Z6Xqfdv0C0hNVKvzrPjZENrpWDt4p4odeVO0Iw==
mdast-util-from-markdown@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c"
integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==
dependencies:
"@types/mdast" "^3.0.0"
mdast-util-to-string "^2.0.0"
micromark "~2.11.0"
parse-entities "^2.0.0"
unist-util-stringify-position "^2.0.0"
mdast-util-from-markdown@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.1.tgz#32a6e8f512b416e1f51eb817fc64bd867ebcd9cc"
@ -4486,6 +4554,11 @@ mdast-util-to-string@^1.0.2:
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.6.tgz#7d85421021343b33de1552fc71cb8e5b4ae7536d"
integrity sha512-868pp48gUPmZIhfKrLbaDneuzGiw3OTDjHc5M1kAepR2CWBJ+HpEsm252K4aXdiP5coVZaJPOqGtVU6Po8xnXg==
mdast-util-to-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b"
integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==
mdast-util-to-string@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz#7a5121475556a04e7eddeb67b264aae79d312814"
@ -4821,6 +4894,14 @@ micromark@^4.0.0:
micromark-util-symbol "^2.0.0"
micromark-util-types "^2.0.0"
micromark@~2.11.0:
version "2.11.4"
resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a"
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
dependencies:
debug "^4.0.0"
parse-entities "^2.0.0"
micromatch@4.0.8, micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
@ -5299,6 +5380,18 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-entities@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==
dependencies:
character-entities "^1.0.0"
character-entities-legacy "^1.0.0"
character-reference-invalid "^1.0.0"
is-alphanumerical "^1.0.0"
is-decimal "^1.0.0"
is-hexadecimal "^1.0.0"
parse-entities@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159"