Browse Source

chore: lint code blocks in docs with ESLint

David Sanders 11 months ago
parent
commit
502940b66b
48 changed files with 286 additions and 32 deletions
  1. 21 0
      docs/.eslintrc.json
  2. 6 0
      docs/api/app.md
  3. 5 0
      docs/api/base-window.md
  4. 9 1
      docs/api/browser-window.md
  5. 2 0
      docs/api/command-line-switches.md
  6. 1 0
      docs/api/command-line.md
  7. 2 0
      docs/api/context-bridge.md
  8. 1 0
      docs/api/debugger.md
  9. 5 0
      docs/api/dialog.md
  10. 1 0
      docs/api/dock.md
  11. 1 0
      docs/api/download-item.md
  12. 4 0
      docs/api/message-channel-main.md
  13. 1 0
      docs/api/native-image.md
  14. 1 0
      docs/api/net.md
  15. 8 3
      docs/api/protocol.md
  16. 11 2
      docs/api/session.md
  17. 2 0
      docs/api/structures/printer-info.md
  18. 2 0
      docs/api/structures/trace-config.md
  19. 2 0
      docs/api/system-preferences.md
  20. 1 0
      docs/api/view.md
  21. 2 0
      docs/api/web-contents-view.md
  22. 11 1
      docs/api/web-contents.md
  23. 6 1
      docs/api/web-frame.md
  24. 1 0
      docs/api/web-utils.md
  25. 1 0
      docs/api/webview-tag.md
  26. 1 1
      docs/development/creating-api.md
  27. 4 0
      docs/faq.md
  28. 7 0
      docs/tutorial/asar-archives.md
  29. 8 3
      docs/tutorial/automated-testing.md
  30. 5 0
      docs/tutorial/custom-title-bar.md
  31. 2 0
      docs/tutorial/custom-window-interactions.md
  32. 1 0
      docs/tutorial/dark-mode.md
  33. 2 1
      docs/tutorial/devtools-extension.md
  34. 2 0
      docs/tutorial/esm.md
  35. 1 0
      docs/tutorial/in-app-purchases.md
  36. 6 0
      docs/tutorial/ipc.md
  37. 1 0
      docs/tutorial/launch-app-from-url-in-another-app.md
  38. 1 0
      docs/tutorial/message-ports.md
  39. 1 0
      docs/tutorial/native-file-drag-drop.md
  40. 3 2
      docs/tutorial/performance.md
  41. 1 1
      docs/tutorial/process-model.md
  42. 2 0
      docs/tutorial/quick-start.md
  43. 6 2
      docs/tutorial/security.md
  44. 2 0
      docs/tutorial/tutorial-3-preload.md
  45. 1 0
      docs/tutorial/windows-taskbar.md
  46. 1 0
      package.json
  47. 40 14
      script/lint.js
  48. 81 0
      yarn.lock

+ 21 - 0
docs/.eslintrc.json

@@ -0,0 +1,21 @@
+{
+  "plugins": [
+    "markdown",
+    "unicorn"
+  ],
+  "overrides": [
+    {
+      "files": ["*.md", "**/*.md"],
+      "processor": "markdown/markdown"
+    }
+  ],
+  "rules": {
+    "@typescript-eslint/no-unused-vars": "off",
+    "indent": "off",
+    "no-undef": "off",
+    "no-unused-expressions": "off",
+    "no-unused-vars": "off",
+    "semi": "off",
+    "unicorn/prefer-node-protocol": "error"
+  }
+}

+ 6 - 0
docs/api/app.md

@@ -9,6 +9,7 @@ closed:
 
 ```js
 const { app } = require('electron')
+
 app.on('window-all-closed', () => {
   app.quit()
 })
@@ -1000,6 +1001,7 @@ starts:
 
 ```js
 const { app, BrowserWindow } = require('electron')
+
 let myWindow = null
 
 const additionalData = { myKey: 'myValue' }
@@ -1197,6 +1199,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:
@@ -1308,6 +1312,7 @@ latest version.
 
 ``` js
 const { app } = require('electron')
+
 const path = require('node:path')
 
 const appFolder = path.dirname(process.execPath)
@@ -1381,6 +1386,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

+ 5 - 0
docs/api/base-window.md

@@ -274,7 +274,9 @@ 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
   if (cmd === 'browser-backward') {
@@ -477,6 +479,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 = [
@@ -696,6 +699,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
@@ -951,6 +955,7 @@ a HTML-rendered toolbar. For example:
 
 ```js
 const { BaseWindow } = require('electron')
+
 const win = new BaseWindow()
 
 const toolbarRect = document.getElementById('toolbar').getBoundingClientRect()

+ 9 - 1
docs/api/browser-window.md

@@ -40,7 +40,9 @@ 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()
 })
@@ -353,7 +355,9 @@ 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
   if (cmd === 'browser-backward' && win.webContents.canGoBack()) {
@@ -788,6 +792,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
@@ -1043,6 +1048,7 @@ a HTML-rendered toolbar. For example:
 
 ```js
 const { BrowserWindow } = require('electron')
+
 const win = new BrowserWindow()
 
 const toolbarRect = document.getElementById('toolbar').getBoundingClientRect()
@@ -1195,9 +1201,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')
@@ -1211,6 +1218,7 @@ the following:
 
 ```js
 const { BrowserWindow } = require('electron')
+
 const win = new BrowserWindow()
 
 win.loadURL('http://localhost:8000/post', {

+ 2 - 0
docs/api/command-line-switches.md

@@ -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')
 
@@ -187,6 +188,7 @@ For example:
 
 ```js
 const { app } = require('electron')
+
 app.commandLine.appendSwitch('proxy-bypass-list', '<local>;*.google.com;*foo.com;1.2.3.4:5678')
 ```
 

+ 1 - 0
docs/api/command-line.md

@@ -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')
 ```
 

+ 2 - 0
docs/api/context-bridge.md

@@ -175,7 +175,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')

+ 1 - 0
docs/api/debugger.md

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

+ 5 - 0
docs/api/dialog.md

@@ -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: [
@@ -119,6 +122,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: [

+ 1 - 0
docs/api/dock.md

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

+ 1 - 0
docs/api/download-item.md

@@ -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.

+ 4 - 0
docs/api/message-channel-main.md

@@ -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) => {

+ 1 - 0
docs/api/native-image.md

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

+ 1 - 0
docs/api/net.md

@@ -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')

+ 8 - 3
docs/api/protocol.md

@@ -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')
 
@@ -37,8 +38,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'
@@ -74,6 +76,7 @@ Policy:
 
 ```js
 const { protocol } = require('electron')
+
 protocol.registerSchemesAsPrivileged([
   { scheme: 'foo', privileges: { bypassCSP: true } }
 ])
@@ -126,8 +129,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([
   {
@@ -328,7 +332,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

+ 11 - 2
docs/api/session.md

@@ -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) => {
@@ -851,6 +853,7 @@ verify proc.
 
 ```js
 const { BrowserWindow } = require('electron')
+
 const win = new BrowserWindow()
 
 win.webContents.session.setCertificateVerifyProc((request, callback) => {
@@ -902,6 +905,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.
@@ -950,7 +954,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
@@ -1187,6 +1193,7 @@ automatically.  To clear the handler, call `setBluetoothPairingHandler(null)`.
 
 ```js
 const { app, BrowserWindow, session } = require('electron')
+
 const path = require('node:path')
 
 function createWindow () {
@@ -1455,6 +1462,7 @@ extension to be loaded.
 
 ```js
 const { app, session } = require('electron')
+
 const path = require('node:path')
 
 app.whenReady().then(async () => {
@@ -1573,6 +1581,7 @@ A [`Protocol`](protocol.md) object for this session.
 
 ```js
 const { app, session } = require('electron')
+
 const path = require('node:path')
 
 app.whenReady().then(() => {

+ 2 - 0
docs/api/structures/printer-info.md

@@ -14,6 +14,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',

+ 2 - 0
docs/api/structures/trace-config.md

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

+ 2 - 0
docs/api/system-preferences.md

@@ -6,6 +6,7 @@ Process: [Main](../glossary.md#main-process), [Utility](../glossary.md#utility-p
 
 ```js
 const { systemPreferences } = require('electron')
+
 console.log(systemPreferences.isAeroGlassEnabled())
 ```
 
@@ -191,6 +192,7 @@ not (transparent windows won't work correctly when DWM composition is disabled):
 
 ```js
 const { BrowserWindow, systemPreferences } = require('electron')
+
 const browserOptions = { width: 1000, height: 800 }
 
 // Make the window transparent only if the platform supports it.

+ 1 - 0
docs/api/view.md

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

+ 2 - 0
docs/api/web-contents-view.md

@@ -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/')
 ```

+ 11 - 1
docs/api/web-contents.md

@@ -55,6 +55,7 @@ These methods can be accessed from the `webContents` module:
 
 ```js
 const { webContents } = require('electron')
+
 console.log(webContents)
 ```
 
@@ -446,7 +447,9 @@ 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, {
     type: 'question',
@@ -1100,7 +1103,9 @@ 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()
   console.log(currentURL)
@@ -1767,9 +1772,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()
@@ -1801,7 +1807,9 @@ creation:
 
 ```js
 const { BrowserWindow } = require('electron')
+
 const win = new BrowserWindow()
+
 win.webContents.on('devtools-opened', () => {
   win.webContents.addWorkSpace(__dirname)
 })
@@ -1867,6 +1875,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)
@@ -2124,6 +2133,7 @@ Returns `Promise<void>` - resolves if the page is saved.
 
 ```js
 const { BrowserWindow } = require('electron')
+
 const win = new BrowserWindow()
 
 win.loadURL('https://github.com')

+ 6 - 1
docs/api/web-frame.md

@@ -96,9 +96,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(() => {
@@ -207,11 +209,14 @@ caches.
 
 ```js
 const { webFrame } = require('electron')
+
 console.log(webFrame.getResourceUsage())
 ```
 
 This will generate:
 
+<!-- eslint-skip -->
+
 ```js
 {
   images: {

+ 1 - 0
docs/api/web-utils.md

@@ -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])
 ```

+ 1 - 0
docs/api/webview-tag.md

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

+ 1 - 1
docs/development/creating-api.md

@@ -166,6 +166,6 @@ Add your module to the module list found at `"lib/browser/api/module-list.ts"` l
 
 ```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') }
 ];
 ```

+ 4 - 0
docs/faq.md

@@ -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'
 })

+ 7 - 0
docs/tutorial/asar-archives.md

@@ -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')
@@ -89,8 +92,11 @@ For some cases like verifying the ASAR archive's checksum, we need to read the
 content of an ASAR archive as a file. For this purpose you can use the built-in
 `original-fs` module which provides original `fs` APIs without `asar` support:
 
+<!-- eslint-disable unicorn/prefer-node-protocol -->
+
 ```js
 const originalFs = require('original-fs')
+
 originalFs.readFileSync('/path/to/example.asar')
 ```
 
@@ -99,6 +105,7 @@ the `fs` module:
 
 ```js
 const fs = require('node:fs')
+
 process.noAsar = true
 fs.readFileSync('/path/to/example.asar')
 ```

+ 8 - 3
docs/tutorial/automated-testing.md

@@ -93,9 +93,10 @@ describe('when the make smaller button is clicked', () => {
 or to retrieve other Electron process information:
 
 ```js @ts-nocheck
+import { browser, expect } from '@wdio/globals'
+
 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' }))
 const { name, version } = packageJson
@@ -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({

+ 5 - 0
docs/tutorial/custom-title-bar.md

@@ -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: {

+ 2 - 0
docs/tutorial/custom-window-interactions.md

@@ -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({

+ 1 - 0
docs/tutorial/dark-mode.md

@@ -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 = () => {

+ 2 - 1
docs/tutorial/devtools-extension.md

@@ -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(

+ 2 - 0
docs/tutorial/esm.md

@@ -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-disable import/newline-after-import, import/order, no-var, quotes -->
+
 ```js @nolint @ts-nocheck title='@babel/plugin-transform-modules-commonjs'
 import foo from "foo";
 import { bar } from "bar";

+ 1 - 0
docs/tutorial/in-app-purchases.md

@@ -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.

+ 6 - 0
docs/tutorial/ipc.md

@@ -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)
 ```

+ 1 - 0
docs/tutorial/launch-app-from-url-in-another-app.md

@@ -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')
 ```
 

+ 1 - 0
docs/tutorial/message-ports.md

@@ -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 () => {

+ 1 - 0
docs/tutorial/native-file-drag-drop.md

@@ -22,6 +22,7 @@ In `preload.js` use the [`contextBridge`][] to inject a method `window.electron.
 
 ```js
 const { contextBridge, ipcRenderer } = require('electron')
+
 const path = require('node:path')
 
 contextBridge.exposeInMainWorld('electron', {

+ 3 - 2
docs/tutorial/performance.md

@@ -173,10 +173,11 @@ in the fictitious `.foo` format. In order to do that, it relies on the
 equally fictitious `foo-parser` module. In traditional Node.js development,
 you might write code that eagerly loads dependencies:
 
-```js title='parser.js' @ts-expect-error=[2]
-const fs = require('node:fs')
+```js title='parser.js' @ts-expect-error=[1]
 const fooParser = require('foo-parser')
 
+const fs = require('node:fs')
+
 class Parser {
   constructor () {
     this.files = fs.readdirSync('.')

+ 1 - 1
docs/tutorial/process-model.md

@@ -241,8 +241,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

+ 2 - 0
docs/tutorial/quick-start.md

@@ -291,6 +291,7 @@ to the `webPreferences.preload` option in your existing `BrowserWindow` construc
 
 ```js
 const { app, BrowserWindow } = require('electron')
+
 // include the Node.js 'path' module at the top of your file
 const path = require('node:path')
 
@@ -358,6 +359,7 @@ The full code is available below:
 
 // Modules to control application life and create native browser window
 const { app, BrowserWindow } = require('electron')
+
 const path = require('node:path')
 
 const createWindow = () => {

+ 6 - 2
docs/tutorial/security.md

@@ -280,7 +280,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')
@@ -610,9 +611,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)
@@ -689,12 +691,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')
 ```
 

+ 2 - 0
docs/tutorial/tutorial-3-preload.md

@@ -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 = () => {

+ 1 - 0
docs/tutorial/windows-taskbar.md

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

+ 1 - 0
package.json

@@ -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",

+ 40 - 14
script/lint.js

@@ -75,6 +75,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';
@@ -148,20 +166,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);
     }
@@ -364,6 +370,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);
     }

+ 81 - 0
yarn.lock

@@ -1819,16 +1819,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@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-2.0.0.tgz#57f4d00974c696e8f74e9f493e7fcb75b44d7ee7"
   integrity sha512-YwaEtEvWLpFa6Wh3uVLrvirA/ahr9fki/NUd/Bd4OR6EdJ8D22hovYQEOUCBfQfcqnC4IAMGMsHXY1eXgL4ZZA==
 
+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"
@@ -2628,6 +2643,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"
@@ -3648,11 +3670,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"
@@ -3759,6 +3794,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"
@@ -3793,6 +3833,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"
@@ -4462,6 +4507,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@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.0.tgz#0214124154f26154a2b3f9d401155509be45e894"
@@ -4530,6 +4586,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@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9"
@@ -4954,6 +5015,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"
+
 [email protected]:
   version "4.0.5"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
@@ -5459,6 +5528,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@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-3.0.0.tgz#9ed6d6569b6cfc95ade058d683ddef239dad60dc"