From 39cc886eed6914bcffd9815161f764c3c7a23d35 Mon Sep 17 00:00:00 2001 From: Tomislav Jovanovic Date: Sat, 6 Jan 2024 01:55:40 +0000 Subject: [PATCH] Bug 1871127 - Add tsconfig, basic types, and fix or ignore remaining type errors r=robwu Differential Revision: https://phabricator.services.mozilla.com/D196388 --- .../components/extensions/ConduitsChild.sys.mjs | 2 +- toolkit/components/extensions/Extension.sys.mjs | 2 +- .../components/extensions/ExtensionCommon.sys.mjs | 3 + toolkit/components/extensions/ExtensionDNR.sys.mjs | 2 +- .../components/extensions/ExtensionParent.sys.mjs | 2 +- .../extensions/ExtensionStorageIDB.sys.mjs | 1 + .../components/extensions/ExtensionUtils.sys.mjs | 5 +- .../components/extensions/MessageChannel.sys.mjs | 2 + .../extensions/MessageManagerProxy.sys.mjs | 2 + toolkit/components/extensions/Schemas.sys.mjs | 3 + toolkit/components/extensions/tsconfig.json | 56 +++++++ toolkit/components/extensions/types/README.md | 86 +++++++++++ .../types/XPCShellContentUtils.sys.d.mts | 87 +++++++++++ toolkit/components/extensions/types/extensions.ts | 80 ++++++++++ toolkit/components/extensions/types/gecko.ts | 163 +++++++++++++++++++++ toolkit/components/extensions/types/globals.ts | 33 +++++ .../extensions/webrequest/WebRequest.sys.mjs | 1 + 17 files changed, 524 insertions(+), 6 deletions(-) create mode 100644 toolkit/components/extensions/tsconfig.json create mode 100644 toolkit/components/extensions/types/README.md create mode 100644 toolkit/components/extensions/types/XPCShellContentUtils.sys.d.mts create mode 100644 toolkit/components/extensions/types/extensions.ts create mode 100644 toolkit/components/extensions/types/gecko.ts create mode 100644 toolkit/components/extensions/types/globals.ts diff --git a/toolkit/components/extensions/ConduitsChild.sys.mjs b/toolkit/components/extensions/ConduitsChild.sys.mjs index f2c8dec51e5d..c5774ab39c67 100644 --- a/toolkit/components/extensions/ConduitsChild.sys.mjs +++ b/toolkit/components/extensions/ConduitsChild.sys.mjs @@ -88,7 +88,7 @@ export class BaseConduit { * Child side conduit, can only send/receive point-to-point messages via the * one specific ConduitsChild actor. */ -class PointConduit extends BaseConduit { +export class PointConduit extends BaseConduit { constructor(subject, address, actor) { super(subject, address); this.actor = actor; diff --git a/toolkit/components/extensions/Extension.sys.mjs b/toolkit/components/extensions/Extension.sys.mjs index 44894cab54ba..d513b0e89a63 100644 --- a/toolkit/components/extensions/Extension.sys.mjs +++ b/toolkit/components/extensions/Extension.sys.mjs @@ -1026,7 +1026,7 @@ export class ExtensionData { /** * Discovers the file names within a directory or JAR file. * - * @param {Ci.nsIFileURL|Ci.nsIJARURI} path + * @param {string} path * The path to the directory or jar file to look at. * @param {boolean} [directoriesOnly] * If true, this will return only the directories present within the directory. diff --git a/toolkit/components/extensions/ExtensionCommon.sys.mjs b/toolkit/components/extensions/ExtensionCommon.sys.mjs index e4cd09c0c884..bb92a34ae736 100644 --- a/toolkit/components/extensions/ExtensionCommon.sys.mjs +++ b/toolkit/components/extensions/ExtensionCommon.sys.mjs @@ -556,6 +556,7 @@ class BaseContext { * @param {object} subject * @param {ConduitAddress} address * @returns {import("ConduitsChild.sys.mjs").PointConduit} + * @type {ConduitOpen} */ openConduit(subject, address) { let wgc = this.contentWindow.windowGlobalChild; @@ -1936,6 +1937,8 @@ class LazyAPIManager extends SchemaAPIManager { this.schemaURLs = schemaURLs; } + + lazyInit() {} } defineLazyGetter(LazyAPIManager.prototype, "schema", function () { diff --git a/toolkit/components/extensions/ExtensionDNR.sys.mjs b/toolkit/components/extensions/ExtensionDNR.sys.mjs index 2757333b3b41..cd01d52b7206 100644 --- a/toolkit/components/extensions/ExtensionDNR.sys.mjs +++ b/toolkit/components/extensions/ExtensionDNR.sys.mjs @@ -1034,7 +1034,7 @@ class RuleValidator { rule.action.redirect ?? {}; const hasExtensionPath = extensionPath != null; const hasRegexSubstitution = regexSubstitution != null; - const redirectKeyCount = + const redirectKeyCount = // @ts-ignore trivial/noisy !!url + !!hasExtensionPath + !!transform + !!hasRegexSubstitution; if (redirectKeyCount !== 1) { if (redirectKeyCount === 0) { diff --git a/toolkit/components/extensions/ExtensionParent.sys.mjs b/toolkit/components/extensions/ExtensionParent.sys.mjs index da90a62954da..4eefc0624787 100644 --- a/toolkit/components/extensions/ExtensionParent.sys.mjs +++ b/toolkit/components/extensions/ExtensionParent.sys.mjs @@ -245,7 +245,7 @@ let apiManager = new (class extends SchemaAPIManager { // to relevant child messengers. Also handles Native messaging and GeckoView. /** @typedef {typeof ProxyMessenger} NativeMessenger */ const ProxyMessenger = { - /** @type {Map>} */ + /** @type {Map&Promise>} */ ports: new Map(), init() { diff --git a/toolkit/components/extensions/ExtensionStorageIDB.sys.mjs b/toolkit/components/extensions/ExtensionStorageIDB.sys.mjs index 3f338aae9076..26df3eacdb91 100644 --- a/toolkit/components/extensions/ExtensionStorageIDB.sys.mjs +++ b/toolkit/components/extensions/ExtensionStorageIDB.sys.mjs @@ -817,6 +817,7 @@ export var ExtensionStorageIDB = { const { ExtensionError } = lazy.ExtensionUtils; if (error instanceof ExtensionError) { + // @ts-ignore (will go away after `lazy` is properly typed) return error; } diff --git a/toolkit/components/extensions/ExtensionUtils.sys.mjs b/toolkit/components/extensions/ExtensionUtils.sys.mjs index 8a5a821efd4f..cbdf900d1414 100644 --- a/toolkit/components/extensions/ExtensionUtils.sys.mjs +++ b/toolkit/components/extensions/ExtensionUtils.sys.mjs @@ -77,6 +77,7 @@ class WorkerExtensionError extends DOMException { * Similar to a WeakMap, but creates a new key with the given * constructor if one is not present. */ +// @ts-ignore (https://github.com/microsoft/TypeScript/issues/56664) class DefaultWeakMap extends WeakMap { constructor(defaultConstructor = undefined, init = undefined) { super(init); @@ -153,7 +154,7 @@ class LimitedSet extends Set { if (this.size >= this.limit + this.slop && !this.has(item)) { this.truncate(this.limit - 1); } - super.add(item); + return super.add(item); } } @@ -259,7 +260,7 @@ function promiseEvent( * * @param {string} topic * The topic to observe. - * @param {function(nsISupports, string): boolean} [test] + * @param {function(any, string): boolean} [test] * An optional test function which, when called with the * observer's subject and data, should return true if this is the * expected notification, false otherwise. diff --git a/toolkit/components/extensions/MessageChannel.sys.mjs b/toolkit/components/extensions/MessageChannel.sys.mjs index bb2445129cd4..65ab2720aa9f 100644 --- a/toolkit/components/extensions/MessageChannel.sys.mjs +++ b/toolkit/components/extensions/MessageChannel.sys.mjs @@ -4,6 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// @ts-nocheck TODO bug 1580774: Remove this file and its uses. + /** * This module provides wrappers around standard message managers to * simplify bidirectional communication. It currently allows a caller to diff --git a/toolkit/components/extensions/MessageManagerProxy.sys.mjs b/toolkit/components/extensions/MessageManagerProxy.sys.mjs index 2e02f4842ac9..387b5876e1e7 100644 --- a/toolkit/components/extensions/MessageManagerProxy.sys.mjs +++ b/toolkit/components/extensions/MessageManagerProxy.sys.mjs @@ -4,6 +4,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// @ts-nocheck TODO: Many references to old types which don't exist anymore. + import { ExtensionUtils } from "resource://gre/modules/ExtensionUtils.sys.mjs"; const { DefaultMap } = ExtensionUtils; diff --git a/toolkit/components/extensions/Schemas.sys.mjs b/toolkit/components/extensions/Schemas.sys.mjs index ff7f926705e5..9107e6a347e5 100644 --- a/toolkit/components/extensions/Schemas.sys.mjs +++ b/toolkit/components/extensions/Schemas.sys.mjs @@ -1528,6 +1528,7 @@ class ChoiceType extends Type { return ["choices", ...super.EXTRA_PROPERTIES]; } + /** @type {(root, schema, path, extraProperties?: Iterable) => ChoiceType} */ static parseSchema(root, schema, path, extraProperties = []) { this.checkSchemaProperties(schema, path, extraProperties); @@ -1628,6 +1629,7 @@ class RefType extends Type { return ["$ref", ...super.EXTRA_PROPERTIES]; } + /** @type {(root, schema, path, extraProperties?: Iterable) => RefType} */ static parseSchema(root, schema, path, extraProperties = []) { this.checkSchemaProperties(schema, path, extraProperties); @@ -3312,6 +3314,7 @@ class Namespace extends Map { return super.keys(); } + /** @returns {Generator<[string, Entry]>} */ *entries() { for (let key of this.keys()) { yield [key, this.get(key)]; diff --git a/toolkit/components/extensions/tsconfig.json b/toolkit/components/extensions/tsconfig.json new file mode 100644 index 000000000000..d569ba9ecae3 --- /dev/null +++ b/toolkit/components/extensions/tsconfig.json @@ -0,0 +1,56 @@ +{ + "include": ["*.mjs", "types/globals.ts"], + "exclude": [], + + "compilerOptions": { + "checkJs": true, + "target": "ESNEXT", + + "declaration": true, + "outDir": "./types", + "typeRoots": [], + "noEmit": true, + + // prettier-ignore + "paths": { + "resource://gre/modules/ConduitsParent.sys.mjs": ["./ConduitsParent.sys.mjs"], + "resource://gre/modules/ConduitsChild.sys.mjs": ["./ConduitsChild.sys.mjs"], + "resource://gre/modules/Extension.sys.mjs": ["./Extension.sys.mjs"], + "resource://gre/modules/ExtensionActivityLog.sys.mjs": ["./ExtensionActivityLog.sys.mjs"], + "resource://gre/modules/ExtensionChild.sys.mjs": ["./ExtensionChild.sys.mjs"], + "resource://gre/modules/ExtensionCommon.sys.mjs": ["./ExtensionCommon.sys.mjs"], + "resource://gre/modules/ExtensionContent.sys.mjs": ["./ExtensionContent.sys.mjs"], + "resource://gre/modules/ExtensionDNR.sys.mjs": ["./ExtensionDNR.sys.mjs"], + "resource://gre/modules/ExtensionDNRLimits.sys.mjs": ["./ExtensionDNRLimits.sys.mjs"], + "resource://gre/modules/ExtensionDNRStore.sys.mjs": ["./ExtensionDNRStore.sys.mjs"], + "resource://gre/modules/ExtensionPageChild.sys.mjs": ["./ExtensionPageChild.sys.mjs"], + "resource://gre/modules/ExtensionParent.sys.mjs": ["./ExtensionParent.sys.mjs"], + "resource://gre/modules/ExtensionPermissionMessages.sys.mjs": ["./ExtensionPermissionMessages.sys.mjs"], + "resource://gre/modules/ExtensionPermissions.sys.mjs": ["./ExtensionPermissions.sys.mjs"], + "resource://gre/modules/ExtensionStorage.sys.mjs": ["./ExtensionStorage.sys.mjs"], + "resource://gre/modules/ExtensionStorageIDB.sys.mjs": ["./ExtensionStorageIDB.sys.mjs"], + "resource://gre/modules/ExtensionStorageSync.sys.mjs": ["./ExtensionStorageSync.sys.mjs"], + "resource://gre/modules/ExtensionTelemetry.sys.mjs": ["./ExtensionTelemetry.sys.mjs"], + "resource://gre/modules/ExtensionUtils.sys.mjs": ["./ExtensionUtils.sys.mjs"], + "resource://gre/modules/ExtensionWorkerChild.sys.mjs": ["./ExtensionWorkerChild.sys.mjs"], + "resource://gre/modules/MessageManagerProxy.sys.mjs": ["./MessageManagerProxy.sys.mjs"], + "resource://gre/modules/NativeManifests.sys.mjs": ["./NativeManifests.sys.mjs"], + "resource://gre/modules/NativeMessaging.sys.mjs": ["./NativeMessaging.sys.mjs"], + "resource://gre/modules/Schemas.sys.mjs": ["./Schemas.sys.mjs"], + "resource://gre/modules/WebNavigationFrames.sys.mjs": ["./WebNavigationFrames.sys.mjs"], + "resource://gre/modules/WebRequest.sys.mjs": ["./webrequest/WebRequest.sys.mjs"], + + // External. + "resource://gre/modules/addons/crypto-utils.sys.mjs": ["../../mozapps/extensions/internal/crypto-utils.sys.mjs"], + "resource://gre/modules/XPCOMUtils.sys.mjs": ["../../../js/xpconnect/loader/XPCOMUtils.sys.mjs"], + "resource://testing-common/ExtensionTestCommon.sys.mjs": ["./ExtensionTestCommon.sys.mjs"], + + // Types for external modules which need fixing, but we don't wanna touch. + "resource://testing-common/XPCShellContentUtils.sys.mjs": ["./types/XPCShellContentUtils.sys.d.mts"], + + // Catch-all redirect for all other modules. + "resource://gre/modules/*.sys.mjs": ["./types/globals.ts"], + "./*": ["./"] + } + } +} diff --git a/toolkit/components/extensions/types/README.md b/toolkit/components/extensions/types/README.md new file mode 100644 index 000000000000..ebd01dec6090 --- /dev/null +++ b/toolkit/components/extensions/types/README.md @@ -0,0 +1,86 @@ +# PoC Type-Checking JavaScript Using JSDocs + +## Intro + +TypeScript can be used on plain JavaScript files documented with JSDoc comments +to check types without a build step. This is a proof of concept to show +viability and benefits of doing this for a "typical" component. + +* [Handbook: Type Checking JavaScript Files][handbook] +* [JSDoc Reference][jsdoc] + +## New files + + * `tsconfig.json`: at the root of a TypeScript "project" configures how to find + and check files. + + * `types/globals.ts`: defines available globals, types and various utilities. + + * `types/XPCShellContentUtils.sys.mts`: an example of type definitions file for + an external module which was automatically generated by `tsc`. + +## How to use and expectations + +Use [npm or yarn to install][download] TypeScript. +Then run `tsc` in the extensions directory to check types: + +``` +mozilla-central/toolkit/components/extensions $ tsc +``` + +You can also use an editor which supports the [language server][langserv]. +VSCode should pick it up automatically, but others like Vim might need +[some configuring][nvim]. + +Other than continuing to use JSDocs, trying to follow guidelines below, and +hopefully remembering to run `tsc` occasionally, for now there is explicitly +*no expectation* that all new code must be fully typed, or pass typecheck +on every commit. + +If you are in a hurry, or run into a confusing type problem, feel free to +slap a @ts-ignore and/or ask for help from someone more familiar. Hopefully +as workflow gets better integrations, we all learn some typescript along +the way, and the whole process remains non-disruptive. + +## Guidelines for type-friendly code + +Using more modern and idiomatic code patterns can enable better type inference +by the TypeScript compiler. + +These fall under 5 main categories: + + 1) Declare and/or initialize all class fields in the constructor. + * (general good practice) + + 2) Use real getters and redefineGetter instead of defineLazyGetter. + * (also keeps related code closer together) + + 3) When extending, don't override class fields with getters, or vice versa. + * https://github.com/microsoft/TypeScript/pull/33509 + + 4) Declare and assign object literals at the same time, not separately. + * (don't use `let foo;` at the top of the file, use `var foo = {`) + + 5) Don't re-use local variables unnecessarily with different types. + * (general good practice, local variables are "free") + +### @ts-ignore recommendations + +*Don't* use `@ts-ignore` for class fields and function or method signatures. + +*Feel free* to use it: + * locally inside methods, + * when the alternative is more noise than signal, + * when doing so isn't preventing passthrough of type-inference through other + parts of the codebase. + + +[handbook]: https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html + +[jsdoc]: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html + +[download]: https://www.typescriptlang.org/download + +[langserv]: https://github.com/typescript-language-server/typescript-language-server + +[nvim]: https://www.reddit.com/r/neovim/comments/131l9cw/theres_another_typescript_lsp_that_wraps_the/ diff --git a/toolkit/components/extensions/types/XPCShellContentUtils.sys.d.mts b/toolkit/components/extensions/types/XPCShellContentUtils.sys.d.mts new file mode 100644 index 000000000000..a2c90c4be179 --- /dev/null +++ b/toolkit/components/extensions/types/XPCShellContentUtils.sys.d.mts @@ -0,0 +1,87 @@ +// @ts-nocheck + +export namespace XPCShellContentUtils { + const currentScope: any; + const fetchScopes: Map; + function initCommon(scope: any): void; + function init(scope: any): void; + function initMochitest(scope: any): void; + function ensureInitialized(scope: any): void; + /** + * Creates a new HttpServer for testing, and begins listening on the + * specified port. Automatically shuts down the server when the test + * unit ends. + * + * @param {object} [options = {}] + * The options object. + * @param {integer} [options.port = -1] + * The port to listen on. If omitted, listen on a random + * port. The latter is the preferred behavior. + * @param {sequence?} [options.hosts = null] + * A set of hosts to accept connections to. Support for this is + * implemented using a proxy filter. + * + * @returns {HttpServer} + * The HTTP server instance. + */ + function createHttpServer({ port, hosts }?: { + port?: number; + hosts?: sequence; + }): HttpServer; + + var remoteContentScripts: boolean; + type ContentPage = ContentPage; + + function registerJSON(server: any, path: any, obj: any): void; + function fetch(origin: any, url: any, options: any): Promise; + /** + * Loads a content page into a hidden docShell. + * + * @param {string} url + * The URL to load. + * @param {object} [options = {}] + * @param {ExtensionWrapper} [options.extension] + * If passed, load the URL as an extension page for the given + * extension. + * @param {boolean} [options.remote] + * If true, load the URL in a content process. If false, load + * it in the parent process. + * @param {boolean} [options.remoteSubframes] + * If true, load cross-origin frames in separate content processes. + * This is ignored if |options.remote| is false. + * @param {string} [options.redirectUrl] + * An optional URL that the initial page is expected to + * redirect to. + * + * @returns {ContentPage} + */ + function loadContentPage(url: string, { extension, remote, remoteSubframes, redirectUrl, privateBrowsing, userContextId, }?: { + extension?: any; + remote?: boolean; + remoteSubframes?: boolean; + redirectUrl?: string; + }): ContentPage; +} +declare class ContentPage { + constructor(remote?: any, remoteSubframes?: any, extension?: any, privateBrowsing?: boolean, userContextId?: any); + remote: any; + remoteSubframes: any; + extension: any; + privateBrowsing: boolean; + userContextId: any; + browserReady: Promise; + _initBrowser(): Promise; + windowlessBrowser: any; + browser: Element; + get browsingContext(): any; + get SpecialPowers(): any; + loadFrameScript(func: any): void; + addFrameScriptHelper(func: any): void; + didChangeBrowserRemoteness(event: any): void; + loadURL(url: any, redirectUrl?: any): Promise; + fetch(...args: any[]): Promise; + spawn(params: any, task: any): any; + legacySpawn(params: any, task: any): any; + close(): Promise; +} +export {}; diff --git a/toolkit/components/extensions/types/extensions.ts b/toolkit/components/extensions/types/extensions.ts new file mode 100644 index 000000000000..8f9555421b74 --- /dev/null +++ b/toolkit/components/extensions/types/extensions.ts @@ -0,0 +1,80 @@ +/** + * Type declarations for WebExtensions framework code. + */ + +// This has every possible property we import from all modules, which is not +// great, but should be manageable and easy to generate for each component. +// ESLint warns if we use one which is not actually defined, so still safe. +type LazyAll = { + BroadcastConduit: typeof import("ConduitsParent.sys.mjs").BroadcastConduit, + Extension: typeof import("Extension.sys.mjs").Extension, + ExtensionActivityLog: typeof import("ExtensionActivityLog.sys.mjs").ExtensionActivityLog, + ExtensionChild: typeof import("ExtensionChild.sys.mjs").ExtensionChild, + ExtensionCommon: typeof import("ExtensionCommon.sys.mjs").ExtensionCommon, + ExtensionContent: typeof import("ExtensionContent.sys.mjs").ExtensionContent, + ExtensionDNR: typeof import("ExtensionDNR.sys.mjs").ExtensionDNR, + ExtensionDNRLimits: typeof import("ExtensionDNRLimits.sys.mjs").ExtensionDNRLimits, + ExtensionDNRStore: typeof import("ExtensionDNRStore.sys.mjs").ExtensionDNRStore, + ExtensionData: typeof import("Extension.sys.mjs").ExtensionData, + ExtensionPageChild: typeof import("ExtensionPageChild.sys.mjs").ExtensionPageChild, + ExtensionParent: typeof import("ExtensionParent.sys.mjs").ExtensionParent, + ExtensionPermissions: typeof import("ExtensionPermissions.sys.mjs").ExtensionPermissions, + ExtensionStorage: typeof import("ExtensionStorage.sys.mjs").ExtensionStorage, + ExtensionStorageIDB: typeof import("ExtensionStorageIDB.sys.mjs").ExtensionStorageIDB, + ExtensionTelemetry: typeof import("ExtensionTelemetry.sys.mjs").ExtensionTelemetry, + ExtensionTestCommon: typeof import("resource://testing-common/ExtensionTestCommon.sys.mjs").ExtensionTestCommon, + ExtensionUtils: typeof import("ExtensionUtils.sys.mjs").ExtensionUtils, + ExtensionWorkerChild: typeof import("ExtensionWorkerChild.sys.mjs").ExtensionWorkerChild, + GeckoViewConnection: typeof import("resource://gre/modules/GeckoViewWebExtension.sys.mjs").GeckoViewConnection, + JSONFile: typeof import("resource://gre/modules/JSONFile.sys.mjs").JSONFile, + Management: typeof import("Extension.sys.mjs").Management, + MessageManagerProxy: typeof import("MessageManagerProxy.sys.mjs").MessageManagerProxy, + NativeApp: typeof import("NativeMessaging.sys.mjs").NativeApp, + NativeManifests: typeof import("NativeManifests.sys.mjs").NativeManifests, + PERMISSION_L10N: typeof import("ExtensionPermissionMessages.sys.mjs").PERMISSION_L10N, + QuarantinedDomains: typeof import("ExtensionPermissions.sys.mjs").QuarantinedDomains, + SchemaRoot: typeof import("Schemas.sys.mjs").SchemaRoot, + Schemas: typeof import("Schemas.sys.mjs").Schemas, + WebNavigationFrames: typeof import("WebNavigationFrames.sys.mjs").WebNavigationFrames, + WebRequest: typeof import("webrequest/WebRequest.sys.mjs").WebRequest, + extensionStorageSync: typeof import("ExtensionStorageSync.sys.mjs").extensionStorageSync, + getErrorNameForTelemetry: typeof import("ExtensionTelemetry.sys.mjs").getErrorNameForTelemetry, + getTrimmedString: typeof import("ExtensionTelemetry.sys.mjs").getTrimmedString, +}; + +// Utility type to extract all strings from a const array, to use as keys. +type Items = A extends ReadonlyArray ? U : never; + +declare global { + type Lazy = Pick & { [k: string]: any }; + + // Export JSDoc types, and make other classes available globally. + type ConduitAddress = import("ConduitsParent.sys.mjs").ConduitAddress; + type ConduitID = import("ConduitsParent.sys.mjs").ConduitID; + type Extension = import("Extension.sys.mjs").Extension; + + // Something about Class type not being exported when nested in a namespace? + type BaseContext = InstanceType; + type BrowserExtensionContent = InstanceType; + type EventEmitter = InstanceType; + type ExtensionAPI = InstanceType; + type ExtensionError = InstanceType; + type LocaleData = InstanceType; + type ProxyAPIImplementation = InstanceType; + type SchemaAPIInterface = InstanceType; + type WorkerExtensionError = InstanceType; + + // Other misc types. + type AddonWrapper = any; + type Context = BaseContext; + type NativeTab = Element; + type SavedFrame = object; + + // Can't define a const generic parameter in jsdocs yet. + // https://github.com/microsoft/TypeScript/issues/56634 + type ConduitInit = ConduitAddress & { send: Send; }; + type Conduit = import("../ConduitsChild.sys.mjs").PointConduit & { [s in `send${Items}`]: callback }; + type ConduitOpen = (subject: object, address: ConduitInit) => Conduit; +} + +export {} diff --git a/toolkit/components/extensions/types/gecko.ts b/toolkit/components/extensions/types/gecko.ts new file mode 100644 index 000000000000..f6b5190f8d29 --- /dev/null +++ b/toolkit/components/extensions/types/gecko.ts @@ -0,0 +1,163 @@ +/** + * Global Gecko type declarations. + */ + +// @ts-ignore +import type { CiClass } from "lib.gecko.xpidl" + +declare global { + // Other misc types. + type Browser = InstanceType; + type bytestring = string; + type callback = (...args: any[]) => any; + type ColorArray = number[]; + type integer = number; + type JSONValue = null | boolean | number | string | JSONValue[] | { [key: string]: JSONValue }; + + interface Document { + createXULElement(name: string): Element; + documentReadyForIdle: Promise; + } + interface EventTarget { + ownerGlobal: Window; + } + interface Error { + code; + } + interface ErrorConstructor { + new (message?: string, options?: ErrorOptions, lineNo?: number): Error; + } + interface Window { + gBrowser; + } + // HACK to get the static isInstance for DOMException and Window? + interface Object { + isInstance(object: any): boolean; + } + + // XPIDL additions/overrides. + + interface nsISupports { + // OMG it works! + QueryInterface?>(aCiClass: T): T['prototype']; + wrappedJSObject?: object; + } + interface nsIProperties { + get>(prop: string, aCiClass: T): T['prototype']; + } + interface nsIPrefBranch { + getComplexValue>(aPrefName: string, aCiClass: T): T['prototype']; + } + // TODO: incorporate above into lib.xpidl.d.ts generation, somehow? + + type Sandbox = typeof globalThis; + interface nsIXPCComponents_utils_Sandbox { + (principal: nsIPrincipal | nsIPrincipal[], options: object): Sandbox; + } + interface nsIXPCComponents_Utils { + cloneInto(obj: T, ...args: any[]): T; + createObjectIn(Sandbox, options?: T): T; + exportFunction(f: T, ...args: any[]): T; + getWeakReference(T): { get(): T }; + readonly Sandbox: nsIXPCComponents_utils_Sandbox; + waiveXrays(obj: T): T; + } + interface nsIDOMWindow extends Window { + docShell: nsIDocShell; + } + interface Document { + documentURIObject: nsIURI; + createXULElement(name: string): Element; + } + + // nsDocShell is the only thing implementing nsIDocShell, but it also + // implements nsIWebNavigation, and a few others, so this is "ok". + interface nsIDocShell extends nsIWebNavigation {} + interface nsISimpleEnumerator extends Iterable {} + + namespace Components { + type Exception = Error; + } + namespace UrlbarUtils { + type RESULT_TYPE = any; + type RESULT_SOURCE = any; + } + + // Various mozilla globals. + var Cc, Cr, ChromeUtils, Components, dump, uneval; + + // [ChromeOnly] WebIDL, to be generated. + var BrowsingContext, ChannelWrapper, ChromeWindow, ChromeWorker, + ClonedErrorHolder, Glean, InspectorUtils, IOUtils, JSProcessActorChild, + JSProcessActorParent, JSWindowActor, JSWindowActorChild, + JSWindowActorParent, L10nRegistry, L10nFileSource, Localization, + MatchGlob, MatchPattern, MatchPatternSet, PathUtils, PreloadedScript, + StructuredCloneHolder, TelemetryStopwatch, WindowGlobalChild, + WebExtensionContentScript, WebExtensionParentActor, WebExtensionPolicy, + XULBrowserElement, nsIMessageListenerManager; + + interface XULElement extends Element {} + + // nsIServices is not a thing. + interface nsIServices { + scriptloader: mozIJSSubScriptLoader; + locale: mozILocaleService; + intl: mozIMozIntl; + storage: mozIStorageService; + appShell: nsIAppShellService; + startup: nsIAppStartup; + blocklist: nsIBlocklistService; + cache2: nsICacheStorageService; + catMan: nsICategoryManager; + clearData: nsIClearDataService; + clipboard: nsIClipboard; + console: nsIConsoleService; + cookieBanners: nsICookieBannerService; + cookies: nsICookieManager & nsICookieService; + appinfo: nsICrashReporter & nsIXULAppInfo & nsIXULRuntime; + DAPTelemetry: nsIDAPTelemetry; + DOMRequest: nsIDOMRequestService; + dns: nsIDNSService; + dirsvc: nsIDirectoryService & nsIProperties; + droppedLinkHandler: nsIDroppedLinkHandler; + eTLD: nsIEffectiveTLDService; + policies: nsIEnterprisePolicies; + env: nsIEnvironment; + els: nsIEventListenerService; + fog: nsIFOG; + focus: nsIFocusManager; + io: nsIIOService & nsINetUtil & nsISpeculativeConnect; + loadContextInfo: nsILoadContextInfoFactory; + domStorageManager: nsIDOMStorageManager & nsILocalStorageManager; + logins: nsILoginManager; + obs: nsIObserverService; + perms: nsIPermissionManager; + prefs: nsIPrefBranch & nsIPrefService; + profiler: nsIProfiler; + prompt: nsIPromptService; + sysinfo: nsISystemInfo & nsIPropertyBag2; + qms: nsIQuotaManagerService; + rfp: nsIRFPService; + scriptSecurityManager: nsIScriptSecurityManager; + search: nsISearchService; + sessionStorage: nsISessionStorageService; + strings: nsIStringBundleService; + telemetry: nsITelemetry; + textToSubURI: nsITextToSubURI; + tm: nsIThreadManager; + uriFixup: nsIURIFixup; + urlFormatter: nsIURLFormatter; + uuid: nsIUUIDGenerator; + vc: nsIVersionComparator; + wm: nsIWindowMediator; + ww: nsIWindowWatcher; + xulStore: nsIXULStore; + ppmm: any; + cpmm: any; + mm: any; + } + + var Ci: nsIXPCComponents_Interfaces; + var Cu: nsIXPCComponents_Utils; + var Services: nsIServices; +} diff --git a/toolkit/components/extensions/types/globals.ts b/toolkit/components/extensions/types/globals.ts new file mode 100644 index 000000000000..45722828e2c9 --- /dev/null +++ b/toolkit/components/extensions/types/globals.ts @@ -0,0 +1,33 @@ +/** + * Support types for toolkit/components/extensions code. + */ + +/// +/// +/// + +// This now relies on types generated in bug 1872918, or get the built +// artifact tslib directly and put it in your src/node_modules/@types: +// https://phabricator.services.mozilla.com/D197620 +/// + +// Exports for all other external modules redirected to globals.ts. +export var AppConstants, + GeckoViewConnection, GeckoViewWebExtension, IndexedDB, JSONFile, Log; + +/** + * This is a mock for the "class" from EventEmitter.sys.mjs. When we import + * it in extensions code using resource://gre/modules/EventEmitter.sys.mjs, + * the catch-all rule from tsconfig.json redirects it to this file. The export + * of the class below fulfills the import. The mock is needed when we subclass + * that EventEmitter, typescript gets confused because it's an old style + * function-and-prototype-based "class", and some types don't match up. + * + * TODO: Convert EventEmitter.sys.mjs into a proper class. + */ +export declare class EventEmitter { + on(event: string, listener: callback): void; + once(event: string, listener: callback): Promise; + off(event: string, listener: callback): void; + emit(event: string, ...args: any[]): void; +} diff --git a/toolkit/components/extensions/webrequest/WebRequest.sys.mjs b/toolkit/components/extensions/webrequest/WebRequest.sys.mjs index 9986ed488644..1d9bbb22607a 100644 --- a/toolkit/components/extensions/webrequest/WebRequest.sys.mjs +++ b/toolkit/components/extensions/webrequest/WebRequest.sys.mjs @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// @ts-nocheck Defer for now. const { nsIHttpActivityObserver, nsISocketTransport } = Ci; -- 2.11.4.GIT