diff --git a/docs/api/dialog.md b/docs/api/dialog.md index ac526fa50cd7..356621d748f5 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -115,7 +115,7 @@ dialog.showOpenDialogSync(mainWindow, { Returns `Promise` - Resolve with an object containing the following: * `canceled` Boolean - whether or not the dialog was canceled. -* `filePaths` String[] (optional) - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. +* `filePaths` String[] - An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array. * `bookmarks` String[] (optional) _macOS_ _mas_ - An array matching the `filePaths` array of base64 encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated. The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal. diff --git a/filenames.auto.gni b/filenames.auto.gni index c09c15a2e935..b6822d11515b 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -126,13 +126,13 @@ auto_filenames = { "lib/common/api/module-list.js", "lib/common/api/native-image.js", "lib/common/api/shell.js", - "lib/common/buffer-utils.js", - "lib/common/clipboard-utils.js", + "lib/common/buffer-utils.ts", + "lib/common/clipboard-utils.ts", "lib/common/crash-reporter.js", "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/common/is-promise.ts", - "lib/common/web-view-methods.js", + "lib/common/web-view-methods.ts", "lib/renderer/api/crash-reporter.js", "lib/renderer/api/desktop-capturer.ts", "lib/renderer/api/ipc-renderer.js", @@ -166,7 +166,7 @@ auto_filenames = { isolated_bundle_deps = [ "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/isolated_renderer/init.js", "lib/renderer/ipc-renderer-internal-utils.ts", "lib/renderer/ipc-renderer-internal.ts", @@ -180,7 +180,7 @@ auto_filenames = { content_script_bundle_deps = [ "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/content_script/init.js", "lib/renderer/chrome-api.ts", "lib/renderer/extensions/event.ts", @@ -241,7 +241,7 @@ auto_filenames = { "lib/browser/crash-reporter-init.js", "lib/browser/default-menu.ts", "lib/browser/desktop-capturer.ts", - "lib/browser/devtools.js", + "lib/browser/devtools.ts", "lib/browser/guest-view-manager.js", "lib/browser/guest-window-manager.js", "lib/browser/init.ts", @@ -257,16 +257,16 @@ auto_filenames = { "lib/common/api/module-list.js", "lib/common/api/native-image.js", "lib/common/api/shell.js", - "lib/common/buffer-utils.js", - "lib/common/clipboard-utils.js", + "lib/common/buffer-utils.ts", + "lib/common/clipboard-utils.ts", "lib/common/crash-reporter.js", "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/common/init.ts", "lib/common/is-promise.ts", "lib/common/parse-features-string.js", "lib/common/reset-search-paths.ts", - "lib/common/web-view-methods.js", + "lib/common/web-view-methods.ts", "lib/renderer/ipc-renderer-internal-utils.ts", "lib/renderer/ipc-renderer-internal.ts", "package.json", @@ -282,15 +282,15 @@ auto_filenames = { "lib/common/api/module-list.js", "lib/common/api/native-image.js", "lib/common/api/shell.js", - "lib/common/buffer-utils.js", - "lib/common/clipboard-utils.js", + "lib/common/buffer-utils.ts", + "lib/common/clipboard-utils.ts", "lib/common/crash-reporter.js", "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/common/init.ts", "lib/common/is-promise.ts", "lib/common/reset-search-paths.ts", - "lib/common/web-view-methods.js", + "lib/common/web-view-methods.ts", "lib/renderer/api/crash-reporter.js", "lib/renderer/api/desktop-capturer.ts", "lib/renderer/api/exports/electron.js", @@ -332,11 +332,11 @@ auto_filenames = { "lib/common/api/module-list.js", "lib/common/api/native-image.js", "lib/common/api/shell.js", - "lib/common/buffer-utils.js", - "lib/common/clipboard-utils.js", + "lib/common/buffer-utils.ts", + "lib/common/clipboard-utils.ts", "lib/common/crash-reporter.js", "lib/common/electron-binding-setup.ts", - "lib/common/error-utils.js", + "lib/common/error-utils.ts", "lib/common/init.ts", "lib/common/is-promise.ts", "lib/common/reset-search-paths.ts", diff --git a/lib/browser/devtools.js b/lib/browser/devtools.ts similarity index 75% rename from lib/browser/devtools.js rename to lib/browser/devtools.ts index 028ac2ffb83b..1a7b3caf764e 100644 --- a/lib/browser/devtools.js +++ b/lib/browser/devtools.ts @@ -1,14 +1,12 @@ -'use strict' - -const { dialog, Menu } = require('electron') -const fs = require('fs') -const url = require('url') +import { dialog, Menu } from 'electron' +import * as fs from 'fs' +import * as url from 'url' const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils') -const convertToMenuTemplate = function (items, handler) { +const convertToMenuTemplate = function (items: ContextMenuItem[], handler: (id: number) => void) { return items.map(function (item) { - const transformed = item.type === 'subMenu' ? { + const transformed: Electron.MenuItemConstructorOptions = item.type === 'subMenu' ? { type: 'submenu', label: item.label, enabled: item.enabled, @@ -34,7 +32,7 @@ const convertToMenuTemplate = function (items, handler) { }) } -const getEditMenuItems = function () { +const getEditMenuItems = function (): Electron.MenuItemConstructorOptions[] { return [ { role: 'undo' }, { role: 'redo' }, @@ -42,18 +40,18 @@ const getEditMenuItems = function () { { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, - { role: 'pasteAndMatchStyle' }, + { role: 'pasteandmatchstyle' }, { role: 'delete' }, - { role: 'selectAll' } + { role: 'selectall' } ] } -const isChromeDevTools = function (pageURL) { +const isChromeDevTools = function (pageURL: string) { const { protocol } = url.parse(pageURL) return protocol === 'devtools:' } -const assertChromeDevTools = function (contents, api) { +const assertChromeDevTools = function (contents: Electron.WebContents, api: string) { const pageURL = contents._getURL() if (!isChromeDevTools(pageURL)) { console.error(`Blocked ${pageURL} from calling ${api}`) @@ -61,7 +59,7 @@ const assertChromeDevTools = function (contents, api) { } } -ipcMainUtils.handle('ELECTRON_INSPECTOR_CONTEXT_MENU', function (event, items, isEditMenu) { +ipcMainUtils.handle('ELECTRON_INSPECTOR_CONTEXT_MENU', function (event: Electron.IpcMainEvent, items: ContextMenuItem[], isEditMenu: boolean) { return new Promise(resolve => { assertChromeDevTools(event.sender, 'window.InspectorFrontendHost.showContextMenuAtPoint()') @@ -73,7 +71,7 @@ ipcMainUtils.handle('ELECTRON_INSPECTOR_CONTEXT_MENU', function (event, items, i }) }) -ipcMainUtils.handle('ELECTRON_INSPECTOR_SELECT_FILE', async function (event) { +ipcMainUtils.handle('ELECTRON_INSPECTOR_SELECT_FILE', async function (event: Electron.IpcMainEvent) { assertChromeDevTools(event.sender, 'window.UI.createFileSelectorElement()') const result = await dialog.showOpenDialog({}) @@ -85,7 +83,7 @@ ipcMainUtils.handle('ELECTRON_INSPECTOR_SELECT_FILE', async function (event) { return [path, data] }) -ipcMainUtils.handle('ELECTRON_INSPECTOR_CONFIRM', async function (event, message = '', title = '') { +ipcMainUtils.handle('ELECTRON_INSPECTOR_CONFIRM', async function (event: Electron.IpcMainEvent, message: string = '', title: string = '') { assertChromeDevTools(event.sender, 'window.confirm()') const options = { diff --git a/lib/common/buffer-utils.js b/lib/common/buffer-utils.ts similarity index 54% rename from lib/common/buffer-utils.js rename to lib/common/buffer-utils.ts index 8bfdf66ee390..01d0786b716f 100644 --- a/lib/common/buffer-utils.js +++ b/lib/common/buffer-utils.ts @@ -1,11 +1,6 @@ -'use strict' +import { Buffer } from 'buffer' -// Note: Don't use destructuring assignment for `Buffer`, or we'll hit a -// browserify bug that makes the statement invalid, throwing an error in -// sandboxed renderer. -const Buffer = require('buffer').Buffer - -const typedArrays = { +const typedArrays: Record = { Buffer, ArrayBuffer, Int8Array, @@ -19,16 +14,18 @@ const typedArrays = { Float64Array } -function getType (value) { +type BufferLike = Buffer | ArrayBuffer | ArrayBufferView + +function getType (value: BufferLike) { for (const type of Object.keys(typedArrays)) { if (value instanceof typedArrays[type]) { return type } } - return null + throw new Error('Invalid buffer') } -function getBuffer (value) { +function getBuffer (value: BufferLike) { if (value instanceof Buffer) { return value } else if (value instanceof ArrayBuffer) { @@ -38,19 +35,27 @@ function getBuffer (value) { } } -exports.isBuffer = function (value) { +export function isBuffer (value: BufferLike) { return ArrayBuffer.isView(value) || value instanceof ArrayBuffer } -exports.bufferToMeta = function (value) { +interface BufferMeta { + type: keyof typeof typedArrays; + data: Buffer; + length: number | undefined; +} + +export function bufferToMeta (value: BufferLike): BufferMeta { return { type: getType(value), data: getBuffer(value), - length: value.length + // NB. We only use length when decoding Int8Array and friends. + // For other buffer-like types this is expected to be undefined. + length: (value as Buffer).length } } -exports.metaToBuffer = function (value) { +export function metaToBuffer (value: BufferMeta) { const constructor = typedArrays[value.type] const data = getBuffer(value.data) @@ -59,7 +64,7 @@ exports.metaToBuffer = function (value) { } else if (constructor === ArrayBuffer) { return data.buffer } else if (constructor) { - return new constructor(data.buffer, data.byteOffset, value.length) + return new (constructor as any)(data.buffer, data.byteOffset, value.length) } else { return data } diff --git a/lib/common/clipboard-utils.js b/lib/common/clipboard-utils.ts similarity index 84% rename from lib/common/clipboard-utils.js rename to lib/common/clipboard-utils.ts index f6e8be74be92..166bf74be562 100644 --- a/lib/common/clipboard-utils.js +++ b/lib/common/clipboard-utils.ts @@ -1,14 +1,12 @@ -'use strict' - const { nativeImage, NativeImage } = process.electronBinding('native_image') -const objectMap = function (source, mapper) { +const objectMap = function (source: Object, mapper: (value: any) => any) { const sourceEntries = Object.entries(source) const targetEntries = sourceEntries.map(([key, val]) => [key, mapper(val)]) return Object.fromEntries(targetEntries) } -const serialize = function (value) { +export function serialize (value: any): any { if (value instanceof NativeImage) { return { buffer: value.toBitmap(), @@ -26,7 +24,7 @@ const serialize = function (value) { } } -const deserialize = function (value) { +export function deserialize (value: any): any { if (value && value.__ELECTRON_SERIALIZED_NativeImage__) { return nativeImage.createFromBitmap(value.buffer, value.size) } else if (Array.isArray(value)) { @@ -39,8 +37,3 @@ const deserialize = function (value) { return value } } - -module.exports = { - serialize, - deserialize -} diff --git a/lib/common/error-utils.js b/lib/common/error-utils.ts similarity index 75% rename from lib/common/error-utils.js rename to lib/common/error-utils.ts index 26dd0185d3f4..b6c084918b22 100644 --- a/lib/common/error-utils.js +++ b/lib/common/error-utils.ts @@ -1,5 +1,3 @@ -'use strict' - const constructors = new Map([ [Error.name, Error], [EvalError.name, EvalError], @@ -10,10 +8,10 @@ const constructors = new Map([ [URIError.name, URIError] ]) -exports.deserialize = function (error) { +export function deserialize (error: Electron.SerializedError): Electron.ErrorWithCause { if (error && error.__ELECTRON_SERIALIZED_ERROR__ && constructors.has(error.name)) { const constructor = constructors.get(error.name) - const deserializedError = new constructor(error.message) + const deserializedError = new constructor!(error.message) as Electron.ErrorWithCause deserializedError.stack = error.stack deserializedError.from = error.from deserializedError.cause = exports.deserialize(error.cause) @@ -22,7 +20,7 @@ exports.deserialize = function (error) { return error } -exports.serialize = function (error) { +export function serialize (error: Electron.ErrorWithCause): Electron.SerializedError { if (error instanceof Error) { // Errors get lost, because: JSON.stringify(new Error('Message')) === {} // Take the serializable properties and construct a generic object @@ -30,7 +28,7 @@ exports.serialize = function (error) { message: error.message, stack: error.stack, name: error.name, - from: process.type, + from: process.type as Electron.ProcessType, cause: exports.serialize(error.cause), __ELECTRON_SERIALIZED_ERROR__: true } diff --git a/lib/common/web-view-methods.js b/lib/common/web-view-methods.ts similarity index 93% rename from lib/common/web-view-methods.js rename to lib/common/web-view-methods.ts index c81655cb438a..f3b6c3c0de31 100644 --- a/lib/common/web-view-methods.js +++ b/lib/common/web-view-methods.ts @@ -1,7 +1,5 @@ -'use strict' - // Public-facing API methods. -exports.syncMethods = new Set([ +export const syncMethods = new Set([ 'getURL', 'getTitle', 'isLoading', @@ -52,7 +50,7 @@ exports.syncMethods = new Set([ 'setZoomLevel' ]) -exports.asyncMethods = new Set([ +export const asyncMethods = new Set([ 'loadURL', 'capturePage', 'executeJavaScript', diff --git a/lib/renderer/inspector.ts b/lib/renderer/inspector.ts index 9e06478f9b25..9739f24c5344 100644 --- a/lib/renderer/inspector.ts +++ b/lib/renderer/inspector.ts @@ -22,7 +22,7 @@ function completeURL (project: string, path: string) { return invokeSync('ELECTRON_INSPECTOR_CONFIRM', message, title) as boolean } -const useEditMenuItems = function (x: number, y: number, items: any[]) { +const useEditMenuItems = function (x: number, y: number, items: ContextMenuItem[]) { return items.length === 0 && document.elementsFromPoint(x, y).some(function (element) { return element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA' || @@ -30,7 +30,7 @@ const useEditMenuItems = function (x: number, y: number, items: any[]) { }) } -const createMenu = function (x: number, y: number, items: any[]) { +const createMenu = function (x: number, y: number, items: ContextMenuItem[]) { const isEditMenu = useEditMenuItems(x, y, items) invoke('ELECTRON_INSPECTOR_CONTEXT_MENU', items, isEditMenu).then(id => { if (typeof id === 'number') { diff --git a/tsconfig.json b/tsconfig.json index 562d65f3f90a..0abc258da456 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "module": "commonjs", "target": "es2017", "lib": [ - "es2017", + "es2019", "dom", "dom.iterable" ], diff --git a/typings/internal-ambient.d.ts b/typings/internal-ambient.d.ts index 8ba166b73746..5801ab94a3a9 100644 --- a/typings/internal-ambient.d.ts +++ b/typings/internal-ambient.d.ts @@ -54,11 +54,20 @@ declare module NodeJS { } } +interface ContextMenuItem { + id: number; + label: string; + type: 'normal' | 'separator' | 'subMenu' | 'checkbox'; + checked: boolean; + enabled: boolean; + subItems: ContextMenuItem[]; +} + declare interface Window { ELECTRON_DISABLE_SECURITY_WARNINGS?: boolean; ELECTRON_ENABLE_SECURITY_WARNINGS?: boolean; InspectorFrontendHost?: { - showContextMenuAtPoint: (x: number, y: number, items: any[]) => void + showContextMenuAtPoint: (x: number, y: number, items: ContextMenuItem[]) => void }; DevToolsAPI?: { contextMenuItemSelected: (id: number) => void; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 94de2cfdfbc5..f2c48a154eae 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -19,6 +19,11 @@ declare namespace Electron { setAppPath(path: string | null): void; } + interface WebContents { + _getURL(): string; + getOwnerBrowserWindow(): Electron.BrowserWindow; + } + interface SerializedError { message: string; stack?: string, @@ -28,6 +33,11 @@ declare namespace Electron { __ELECTRON_SERIALIZED_ERROR__: true } + interface ErrorWithCause extends Error { + from?: string; + cause?: ErrorWithCause; + } + interface InjectionBase { url: string; code: string