diff --git a/src/page.ts b/src/page.ts index ff4ba7acd5..0c74873014 100644 --- a/src/page.ts +++ b/src/page.ts @@ -387,9 +387,9 @@ export class Page extends EventEmitter { async emulateMedia(options: { media?: types.MediaType | null, colorScheme?: types.ColorScheme | null }) { if (options.media !== undefined) - assert(options.media === null || types.mediaTypes.has(options.media), 'media: expected one of (screen|print)'); + assert(options.media === null || types.mediaTypes.has(options.media), 'media: expected one of (screen|print|null)'); if (options.colorScheme !== undefined) - assert(options.colorScheme === null || types.colorSchemes.has(options.colorScheme), 'colorScheme: expected one of (dark|light|no-preference)'); + assert(options.colorScheme === null || types.colorSchemes.has(options.colorScheme), 'colorScheme: expected one of (dark|light|no-preference|null)'); if (options.media !== undefined) this._state.mediaType = options.media; if (options.colorScheme !== undefined) diff --git a/src/rpc/channels.ts b/src/rpc/channels.ts index 8f913c2bcf..a1cb3feef3 100644 --- a/src/rpc/channels.ts +++ b/src/rpc/channels.ts @@ -620,8 +620,8 @@ export type PageCloseParams = { }; export type PageCloseResult = void; export type PageEmulateMediaParams = { - media?: 'screen' | 'print' | 'reset', - colorScheme?: 'dark' | 'light' | 'no-preference' | 'reset', + media?: 'screen' | 'print' | 'null', + colorScheme?: 'dark' | 'light' | 'no-preference' | 'null', }; export type PageEmulateMediaResult = void; export type PageExposeBindingParams = { diff --git a/src/rpc/client/browserType.ts b/src/rpc/client/browserType.ts index b75b08f034..8fed4ca9f0 100644 --- a/src/rpc/client/browserType.ts +++ b/src/rpc/client/browserType.ts @@ -23,6 +23,7 @@ import { BrowserServer } from './browserServer'; import { LoggerSink } from '../../loggerSink'; import { headersObjectToArray, envObjectToArray } from '../serializers'; import { serializeArgument } from './jsHandle'; +import { assert } from '../../helper'; type FirefoxPrefsOptions = { firefoxUserPrefs?: { [key: string]: string | number | boolean } }; @@ -48,6 +49,8 @@ export class BrowserType extends ChannelOwner { + assert(!(options as any).userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead'); + assert(!(options as any).port, 'Cannot specify a port without launching as a server.'); const launchOptions: BrowserTypeLaunchParams = { ...options, ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined, diff --git a/src/rpc/client/channelOwner.ts b/src/rpc/client/channelOwner.ts index b8c51036df..411e13885a 100644 --- a/src/rpc/client/channelOwner.ts +++ b/src/rpc/client/channelOwner.ts @@ -66,7 +66,7 @@ export abstract class ChannelOwner this._connection.sendMessageToServer({ guid, method: String(prop), params }); + return (params: any) => this._connection.sendMessageToServer(this._type, guid, String(prop), params); }, }); (this._channel as any)._object = this; diff --git a/src/rpc/client/connection.ts b/src/rpc/client/connection.ts index 46a49f3cd5..e28257f9b1 100644 --- a/src/rpc/client/connection.ts +++ b/src/rpc/client/connection.ts @@ -38,6 +38,7 @@ import { ChromiumBrowser } from './chromiumBrowser'; import { ChromiumBrowserContext } from './chromiumBrowserContext'; import { Selectors } from './selectors'; import { Stream } from './stream'; +import { validateParams } from './validator'; class Root extends ChannelOwner { constructor(connection: Connection) { @@ -63,9 +64,10 @@ export class Connection { return new Promise(f => this._waitingForObject.set(guid, f)); } - async sendMessageToServer(message: { guid: string, method: string, params: any }): Promise { + async sendMessageToServer(type: string, guid: string, method: string, params: any): Promise { const id = ++this._lastId; - const converted = { id, ...message, params: this._replaceChannelsWithGuids(message.params) }; + const validated = method === 'debugScopeState' ? params : validateParams(type, method, params); + const converted = { id, guid, method, params: validated }; debug('pw:channel:command')(converted); this.onmessage(converted); return new Promise((resolve, reject) => this._callbacks.set(id, { resolve, reject })); @@ -97,22 +99,6 @@ export class Connection { object._channel.emit(method, this._replaceGuidsWithChannels(params)); } - private _replaceChannelsWithGuids(payload: any): any { - if (!payload) - return payload; - if (Array.isArray(payload)) - return payload.map(p => this._replaceChannelsWithGuids(p)); - if (payload._object instanceof ChannelOwner) - return { guid: payload._object._guid }; - if (typeof payload === 'object') { - const result: any = {}; - for (const key of Object.keys(payload)) - result[key] = this._replaceChannelsWithGuids(payload[key]); - return result; - } - return payload; - } - private _replaceGuidsWithChannels(payload: any): any { if (!payload) return payload; diff --git a/src/rpc/client/elementHandle.ts b/src/rpc/client/elementHandle.ts index f3294d6317..1930c8c7f0 100644 --- a/src/rpc/client/elementHandle.ts +++ b/src/rpc/client/elementHandle.ts @@ -123,7 +123,7 @@ export class ElementHandle extends JSHandle { }); } - async selectText(options: types.TimeoutOptions): Promise { + async selectText(options: types.TimeoutOptions = {}): Promise { return this._wrapApiCall('elementHandle.selectText', async () => { await this._elementChannel.selectText(options); }); diff --git a/src/rpc/client/frame.ts b/src/rpc/client/frame.ts index d38fce991f..3b2c9d5d3b 100644 --- a/src/rpc/client/frame.ts +++ b/src/rpc/client/frame.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { assertMaxArguments, helper } from '../../helper'; +import { assertMaxArguments, helper, assert } from '../../helper'; import * as types from '../../types'; import { FrameChannel, FrameInitializer, FrameNavigatedEvent } from '../channels'; import { BrowserContext } from './browserContext'; @@ -89,7 +89,8 @@ export class Frame extends ChannelOwner { async goto(url: string, options: GotoOptions = {}): Promise { return this._wrapApiCall(this._apiName('goto'), async () => { - return network.Response.fromNullable((await this._channel.goto({ url, ...options })).response); + const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); + return network.Response.fromNullable((await this._channel.goto({ url, ...options, waitUntil })).response); }); } @@ -188,6 +189,10 @@ export class Frame extends ChannelOwner { async waitForSelector(selector: string, options: types.WaitForElementOptions = {}): Promise | null> { return this._wrapApiCall(this._apiName('waitForSelector'), async () => { + if ((options as any).visibility) + throw new Error('options.visibility is not supported, did you mean options.state?'); + if ((options as any).waitFor && (options as any).waitFor !== 'visible') + throw new Error('options.waitFor is not supported, did you mean options.state?'); const result = await this._channel.waitForSelector({ selector, ...options }); return ElementHandle.fromNullable(result.element) as ElementHandle | null; }); @@ -234,7 +239,8 @@ export class Frame extends ChannelOwner { async setContent(html: string, options: types.NavigateOptions = {}): Promise { return this._wrapApiCall(this._apiName('setContent'), async () => { - await this._channel.setContent({ html, ...options }); + const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); + await this._channel.setContent({ html, ...options, waitUntil }); }); } @@ -272,9 +278,11 @@ export class Frame extends ChannelOwner { async addStyleTag(options: { url?: string; path?: string; content?: string; }): Promise { return this._wrapApiCall(this._apiName('addStyleTag'), async () => { const copy = { ...options }; - if (copy.path) + if (copy.path) { copy.content = (await fsReadFileAsync(copy.path)).toString(); - return ElementHandle.from((await this._channel.addStyleTag({ ...options })).element); + copy.content += '/*# sourceURL=' + copy.path.replace(/\n/g, '') + '*/'; + } + return ElementHandle.from((await this._channel.addStyleTag({ ...copy })).element); }); } @@ -378,6 +386,8 @@ export class Frame extends ChannelOwner { async waitForFunction(pageFunction: Func1, arg?: any, options?: types.WaitForFunctionOptions): Promise>; async waitForFunction(pageFunction: Func1, arg: Arg, options: types.WaitForFunctionOptions = {}): Promise> { return this._wrapApiCall(this._apiName('waitForFunction'), async () => { + if (typeof options.polling === 'string') + assert(options.polling === 'raf', 'Unknown polling option: ' + options.polling); const result = await this._channel.waitForFunction({ ...options, pollingInterval: options.polling === 'raf' ? undefined : options.polling, @@ -396,7 +406,7 @@ export class Frame extends ChannelOwner { } } -function verifyLoadState(name: string, waitUntil: types.LifecycleEvent): types.LifecycleEvent { +export function verifyLoadState(name: string, waitUntil: types.LifecycleEvent): types.LifecycleEvent { if (waitUntil as unknown === 'networkidle0') waitUntil = 'networkidle'; if (!types.kLifecycleEvents.has(waitUntil)) diff --git a/src/rpc/client/page.ts b/src/rpc/client/page.ts index b5519c02ae..2c7b06e557 100644 --- a/src/rpc/client/page.ts +++ b/src/rpc/client/page.ts @@ -29,7 +29,7 @@ import { Dialog } from './dialog'; import { Download } from './download'; import { ElementHandle } from './elementHandle'; import { Worker } from './worker'; -import { Frame, FunctionWithSource, GotoOptions } from './frame'; +import { Frame, FunctionWithSource, GotoOptions, verifyLoadState } from './frame'; import { Keyboard, Mouse } from './input'; import { Func1, FuncOn, SmartHandle, serializeArgument, parseResult } from './jsHandle'; import { Request, Response, Route, RouteHandler } from './network'; @@ -300,7 +300,8 @@ export class Page extends ChannelOwner { async reload(options: types.NavigateOptions = {}): Promise { return this._wrapApiCall('page.reload', async () => { - return Response.fromNullable((await this._channel.reload(options)).response); + const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); + return Response.fromNullable((await this._channel.reload({ ...options, waitUntil })).response); }); } @@ -346,21 +347,23 @@ export class Page extends ChannelOwner { async goBack(options: types.NavigateOptions = {}): Promise { return this._wrapApiCall('page.goBack', async () => { - return Response.fromNullable((await this._channel.goBack(options)).response); + const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); + return Response.fromNullable((await this._channel.goBack({ ...options, waitUntil })).response); }); } async goForward(options: types.NavigateOptions = {}): Promise { return this._wrapApiCall('page.goForward', async () => { - return Response.fromNullable((await this._channel.goForward(options)).response); + const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil); + return Response.fromNullable((await this._channel.goForward({ ...options, waitUntil })).response); }); } async emulateMedia(options: { media?: types.MediaType | null, colorScheme?: types.ColorScheme | null }) { return this._wrapApiCall('page.emulateMedia', async () => { await this._channel.emulateMedia({ - media: options.media === null ? 'reset' : options.media, - colorScheme: options.colorScheme === null ? 'reset' : options.colorScheme, + media: options.media === null ? 'null' : options.media, + colorScheme: options.colorScheme === null ? 'null' : options.colorScheme, }); }); } diff --git a/src/rpc/client/validator.ts b/src/rpc/client/validator.ts new file mode 100644 index 0000000000..1589184849 --- /dev/null +++ b/src/rpc/client/validator.ts @@ -0,0 +1,1391 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is generated by generate_channels.js, do not edit manually. + +import { scheme, tOptional, tObject, tBoolean, tNumber, tString, tType, tEnum, tArray, tChannel, tUndefined, tBinary } from './validatorPrimitives'; +export { validateParams } from './validatorPrimitives'; + +scheme.SerializedValue = tObject({ + n: tOptional(tNumber), + b: tOptional(tBoolean), + s: tOptional(tString), + v: tOptional(tEnum(['null', 'undefined', 'NaN', 'Infinity', '-Infinity', '-0'])), + d: tOptional(tString), + r: tOptional(tObject({ + p: tString, + f: tString, + })), + a: tOptional(tArray(tType('SerializedValue'))), + o: tOptional(tArray(tObject({ + k: tString, + v: tType('SerializedValue'), + }))), + h: tOptional(tNumber), +}); +scheme.SerializedArgument = tObject({ + value: tType('SerializedValue'), + handles: tArray(tChannel('*')), +}); +scheme.AXNode = tObject({ + role: tString, + name: tString, + valueString: tOptional(tString), + valueNumber: tOptional(tNumber), + description: tOptional(tString), + keyshortcuts: tOptional(tString), + roledescription: tOptional(tString), + valuetext: tOptional(tString), + disabled: tOptional(tBoolean), + expanded: tOptional(tBoolean), + focused: tOptional(tBoolean), + modal: tOptional(tBoolean), + multiline: tOptional(tBoolean), + multiselectable: tOptional(tBoolean), + readonly: tOptional(tBoolean), + required: tOptional(tBoolean), + selected: tOptional(tBoolean), + checked: tOptional(tEnum(['checked', 'unchecked', 'mixed'])), + pressed: tOptional(tEnum(['pressed', 'released', 'mixed'])), + level: tOptional(tNumber), + valuemin: tOptional(tNumber), + valuemax: tOptional(tNumber), + autocomplete: tOptional(tString), + haspopup: tOptional(tString), + invalid: tOptional(tString), + orientation: tOptional(tString), + children: tOptional(tArray(tType('AXNode'))), +}); +scheme.SerializedError = tObject({ + error: tOptional(tObject({ + message: tString, + name: tString, + stack: tOptional(tString), + })), + value: tOptional(tType('SerializedValue')), +}); +scheme.PlaywrightInitializer = tObject({ + chromium: tChannel('BrowserType'), + firefox: tChannel('BrowserType'), + webkit: tChannel('BrowserType'), + electron: tOptional(tChannel('Electron')), + deviceDescriptors: tArray(tObject({ + name: tString, + descriptor: tObject({ + userAgent: tString, + viewport: tObject({ + width: tNumber, + height: tNumber, + }), + deviceScaleFactor: tNumber, + isMobile: tBoolean, + hasTouch: tBoolean, + }), + })), + selectors: tChannel('Selectors'), +}); +scheme.SelectorsInitializer = tObject({}); +scheme.SelectorsRegisterParams = tObject({ + name: tString, + source: tString, + contentScript: tOptional(tBoolean), +}); +scheme.SelectorsRegisterResult = tUndefined; +scheme.SelectorsCreateSelectorParams = tObject({ + name: tString, + handle: tChannel('ElementHandle'), +}); +scheme.SelectorsCreateSelectorResult = tObject({ + value: tOptional(tString), +}); +scheme.BrowserTypeInitializer = tObject({ + executablePath: tString, + name: tString, +}); +scheme.BrowserTypeConnectParams = tObject({ + wsEndpoint: tString, + slowMo: tOptional(tNumber), + timeout: tOptional(tNumber), +}); +scheme.BrowserTypeConnectResult = tObject({ + browser: tChannel('Browser'), +}); +scheme.BrowserTypeLaunchParams = tObject({ + executablePath: tOptional(tString), + args: tOptional(tArray(tString)), + ignoreAllDefaultArgs: tOptional(tBoolean), + ignoreDefaultArgs: tOptional(tArray(tString)), + handleSIGINT: tOptional(tBoolean), + handleSIGTERM: tOptional(tBoolean), + handleSIGHUP: tOptional(tBoolean), + timeout: tOptional(tNumber), + env: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + headless: tOptional(tBoolean), + devtools: tOptional(tBoolean), + proxy: tOptional(tObject({ + server: tString, + bypass: tOptional(tString), + username: tOptional(tString), + password: tOptional(tString), + })), + downloadsPath: tOptional(tString), + firefoxUserPrefs: tOptional(tType('SerializedValue')), + slowMo: tOptional(tNumber), +}); +scheme.BrowserTypeLaunchResult = tObject({ + browser: tChannel('Browser'), +}); +scheme.BrowserTypeLaunchServerParams = tObject({ + executablePath: tOptional(tString), + args: tOptional(tArray(tString)), + ignoreAllDefaultArgs: tOptional(tBoolean), + ignoreDefaultArgs: tOptional(tArray(tString)), + handleSIGINT: tOptional(tBoolean), + handleSIGTERM: tOptional(tBoolean), + handleSIGHUP: tOptional(tBoolean), + timeout: tOptional(tNumber), + env: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + headless: tOptional(tBoolean), + devtools: tOptional(tBoolean), + proxy: tOptional(tObject({ + server: tString, + bypass: tOptional(tString), + username: tOptional(tString), + password: tOptional(tString), + })), + downloadsPath: tOptional(tString), + firefoxUserPrefs: tOptional(tType('SerializedValue')), + port: tOptional(tNumber), +}); +scheme.BrowserTypeLaunchServerResult = tObject({ + server: tChannel('BrowserServer'), +}); +scheme.BrowserTypeLaunchPersistentContextParams = tObject({ + userDataDir: tString, + executablePath: tOptional(tString), + args: tOptional(tArray(tString)), + ignoreAllDefaultArgs: tOptional(tBoolean), + ignoreDefaultArgs: tOptional(tArray(tString)), + handleSIGINT: tOptional(tBoolean), + handleSIGTERM: tOptional(tBoolean), + handleSIGHUP: tOptional(tBoolean), + timeout: tOptional(tNumber), + env: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + headless: tOptional(tBoolean), + devtools: tOptional(tBoolean), + proxy: tOptional(tObject({ + server: tString, + bypass: tOptional(tString), + username: tOptional(tString), + password: tOptional(tString), + })), + downloadsPath: tOptional(tString), + slowMo: tOptional(tNumber), + noDefaultViewport: tOptional(tBoolean), + viewport: tOptional(tObject({ + width: tNumber, + height: tNumber, + })), + ignoreHTTPSErrors: tOptional(tBoolean), + javaScriptEnabled: tOptional(tBoolean), + bypassCSP: tOptional(tBoolean), + userAgent: tOptional(tString), + locale: tOptional(tString), + timezoneId: tOptional(tString), + geolocation: tOptional(tObject({ + longitude: tNumber, + latitude: tNumber, + accuracy: tOptional(tNumber), + })), + permissions: tOptional(tArray(tString)), + extraHTTPHeaders: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + offline: tOptional(tBoolean), + httpCredentials: tOptional(tObject({ + username: tString, + password: tString, + })), + deviceScaleFactor: tOptional(tNumber), + isMobile: tOptional(tBoolean), + hasTouch: tOptional(tBoolean), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), + acceptDownloads: tOptional(tBoolean), +}); +scheme.BrowserTypeLaunchPersistentContextResult = tObject({ + context: tChannel('BrowserContext'), +}); +scheme.BrowserServerInitializer = tObject({ + wsEndpoint: tString, + pid: tNumber, +}); +scheme.BrowserServerCloseEvent = tObject({}); +scheme.BrowserServerCloseParams = tOptional(tObject({})); +scheme.BrowserServerCloseResult = tUndefined; +scheme.BrowserServerKillParams = tOptional(tObject({})); +scheme.BrowserServerKillResult = tUndefined; +scheme.BrowserInitializer = tObject({}); +scheme.BrowserCloseEvent = tObject({}); +scheme.BrowserCloseParams = tOptional(tObject({})); +scheme.BrowserCloseResult = tUndefined; +scheme.BrowserNewContextParams = tObject({ + noDefaultViewport: tOptional(tBoolean), + viewport: tOptional(tObject({ + width: tNumber, + height: tNumber, + })), + ignoreHTTPSErrors: tOptional(tBoolean), + javaScriptEnabled: tOptional(tBoolean), + bypassCSP: tOptional(tBoolean), + userAgent: tOptional(tString), + locale: tOptional(tString), + timezoneId: tOptional(tString), + geolocation: tOptional(tObject({ + longitude: tNumber, + latitude: tNumber, + accuracy: tOptional(tNumber), + })), + permissions: tOptional(tArray(tString)), + extraHTTPHeaders: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + offline: tOptional(tBoolean), + httpCredentials: tOptional(tObject({ + username: tString, + password: tString, + })), + deviceScaleFactor: tOptional(tNumber), + isMobile: tOptional(tBoolean), + hasTouch: tOptional(tBoolean), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), + acceptDownloads: tOptional(tBoolean), +}); +scheme.BrowserNewContextResult = tObject({ + context: tChannel('BrowserContext'), +}); +scheme.BrowserCrNewBrowserCDPSessionParams = tOptional(tObject({})); +scheme.BrowserCrNewBrowserCDPSessionResult = tObject({ + session: tChannel('CDPSession'), +}); +scheme.BrowserCrStartTracingParams = tObject({ + page: tOptional(tChannel('Page')), + path: tOptional(tString), + screenshots: tOptional(tBoolean), + categories: tOptional(tArray(tString)), +}); +scheme.BrowserCrStartTracingResult = tUndefined; +scheme.BrowserCrStopTracingParams = tOptional(tObject({})); +scheme.BrowserCrStopTracingResult = tObject({ + binary: tBinary, +}); +scheme.BrowserContextInitializer = tObject({}); +scheme.BrowserContextBindingCallEvent = tObject({ + binding: tChannel('BindingCall'), +}); +scheme.BrowserContextCloseEvent = tObject({}); +scheme.BrowserContextPageEvent = tObject({ + page: tChannel('Page'), +}); +scheme.BrowserContextRouteEvent = tObject({ + route: tChannel('Route'), + request: tChannel('Request'), +}); +scheme.BrowserContextAddCookiesParams = tObject({ + cookies: tArray(tObject({ + name: tString, + value: tString, + url: tOptional(tString), + domain: tOptional(tString), + path: tOptional(tString), + expires: tOptional(tNumber), + httpOnly: tOptional(tBoolean), + secure: tOptional(tBoolean), + sameSite: tOptional(tEnum(['Strict', 'Lax', 'None'])), + })), +}); +scheme.BrowserContextAddCookiesResult = tUndefined; +scheme.BrowserContextAddInitScriptParams = tObject({ + source: tString, +}); +scheme.BrowserContextAddInitScriptResult = tUndefined; +scheme.BrowserContextClearCookiesParams = tOptional(tObject({})); +scheme.BrowserContextClearCookiesResult = tUndefined; +scheme.BrowserContextClearPermissionsParams = tOptional(tObject({})); +scheme.BrowserContextClearPermissionsResult = tUndefined; +scheme.BrowserContextCloseParams = tOptional(tObject({})); +scheme.BrowserContextCloseResult = tUndefined; +scheme.BrowserContextCookiesParams = tObject({ + urls: tArray(tString), +}); +scheme.BrowserContextCookiesResult = tObject({ + cookies: tArray(tObject({ + name: tString, + value: tString, + domain: tString, + path: tString, + expires: tNumber, + httpOnly: tBoolean, + secure: tBoolean, + sameSite: tEnum(['Strict', 'Lax', 'None']), + })), +}); +scheme.BrowserContextExposeBindingParams = tObject({ + name: tString, +}); +scheme.BrowserContextExposeBindingResult = tUndefined; +scheme.BrowserContextGrantPermissionsParams = tObject({ + permissions: tArray(tString), + origin: tOptional(tString), +}); +scheme.BrowserContextGrantPermissionsResult = tUndefined; +scheme.BrowserContextNewPageParams = tOptional(tObject({})); +scheme.BrowserContextNewPageResult = tObject({ + page: tChannel('Page'), +}); +scheme.BrowserContextSetDefaultNavigationTimeoutNoReplyParams = tObject({ + timeout: tNumber, +}); +scheme.BrowserContextSetDefaultNavigationTimeoutNoReplyResult = tUndefined; +scheme.BrowserContextSetDefaultTimeoutNoReplyParams = tObject({ + timeout: tNumber, +}); +scheme.BrowserContextSetDefaultTimeoutNoReplyResult = tUndefined; +scheme.BrowserContextSetExtraHTTPHeadersParams = tObject({ + headers: tArray(tObject({ + name: tString, + value: tString, + })), +}); +scheme.BrowserContextSetExtraHTTPHeadersResult = tUndefined; +scheme.BrowserContextSetGeolocationParams = tObject({ + geolocation: tOptional(tObject({ + longitude: tNumber, + latitude: tNumber, + accuracy: tOptional(tNumber), + })), +}); +scheme.BrowserContextSetGeolocationResult = tUndefined; +scheme.BrowserContextSetHTTPCredentialsParams = tObject({ + httpCredentials: tOptional(tObject({ + username: tString, + password: tString, + })), +}); +scheme.BrowserContextSetHTTPCredentialsResult = tUndefined; +scheme.BrowserContextSetNetworkInterceptionEnabledParams = tObject({ + enabled: tBoolean, +}); +scheme.BrowserContextSetNetworkInterceptionEnabledResult = tUndefined; +scheme.BrowserContextSetOfflineParams = tObject({ + offline: tBoolean, +}); +scheme.BrowserContextSetOfflineResult = tUndefined; +scheme.BrowserContextCrBackgroundPageEvent = tObject({ + page: tChannel('Page'), +}); +scheme.BrowserContextCrServiceWorkerEvent = tObject({ + worker: tChannel('Worker'), +}); +scheme.BrowserContextCrNewCDPSessionParams = tObject({ + page: tChannel('Page'), +}); +scheme.BrowserContextCrNewCDPSessionResult = tObject({ + session: tChannel('CDPSession'), +}); +scheme.PageInitializer = tObject({ + mainFrame: tChannel('Frame'), + viewportSize: tOptional(tObject({ + width: tNumber, + height: tNumber, + })), + isClosed: tBoolean, +}); +scheme.PageBindingCallEvent = tObject({ + binding: tChannel('BindingCall'), +}); +scheme.PageCloseEvent = tObject({}); +scheme.PageConsoleEvent = tObject({ + message: tChannel('ConsoleMessage'), +}); +scheme.PageCrashEvent = tObject({}); +scheme.PageDialogEvent = tObject({ + dialog: tChannel('Dialog'), +}); +scheme.PageDownloadEvent = tObject({ + download: tChannel('Download'), +}); +scheme.PageDomcontentloadedEvent = tObject({}); +scheme.PageFileChooserEvent = tObject({ + element: tChannel('ElementHandle'), + isMultiple: tBoolean, +}); +scheme.PageFrameAttachedEvent = tObject({ + frame: tChannel('Frame'), +}); +scheme.PageFrameDetachedEvent = tObject({ + frame: tChannel('Frame'), +}); +scheme.PageLoadEvent = tObject({}); +scheme.PagePageErrorEvent = tObject({ + error: tType('SerializedError'), +}); +scheme.PagePopupEvent = tObject({ + page: tChannel('Page'), +}); +scheme.PageRequestEvent = tObject({ + request: tChannel('Request'), +}); +scheme.PageRequestFailedEvent = tObject({ + request: tChannel('Request'), + failureText: tOptional(tString), +}); +scheme.PageRequestFinishedEvent = tObject({ + request: tChannel('Request'), +}); +scheme.PageResponseEvent = tObject({ + response: tChannel('Response'), +}); +scheme.PageRouteEvent = tObject({ + route: tChannel('Route'), + request: tChannel('Request'), +}); +scheme.PageWorkerEvent = tObject({ + worker: tChannel('Worker'), +}); +scheme.PageSetDefaultNavigationTimeoutNoReplyParams = tObject({ + timeout: tNumber, +}); +scheme.PageSetDefaultNavigationTimeoutNoReplyResult = tUndefined; +scheme.PageSetDefaultTimeoutNoReplyParams = tObject({ + timeout: tNumber, +}); +scheme.PageSetDefaultTimeoutNoReplyResult = tUndefined; +scheme.PageSetFileChooserInterceptedNoReplyParams = tObject({ + intercepted: tBoolean, +}); +scheme.PageSetFileChooserInterceptedNoReplyResult = tUndefined; +scheme.PageAddInitScriptParams = tObject({ + source: tString, +}); +scheme.PageAddInitScriptResult = tUndefined; +scheme.PageCloseParams = tObject({ + runBeforeUnload: tOptional(tBoolean), +}); +scheme.PageCloseResult = tUndefined; +scheme.PageEmulateMediaParams = tObject({ + media: tOptional(tEnum(['screen', 'print', 'null'])), + colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference', 'null'])), +}); +scheme.PageEmulateMediaResult = tUndefined; +scheme.PageExposeBindingParams = tObject({ + name: tString, +}); +scheme.PageExposeBindingResult = tUndefined; +scheme.PageGoBackParams = tObject({ + timeout: tOptional(tNumber), + waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.PageGoBackResult = tObject({ + response: tOptional(tChannel('Response')), +}); +scheme.PageGoForwardParams = tObject({ + timeout: tOptional(tNumber), + waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.PageGoForwardResult = tObject({ + response: tOptional(tChannel('Response')), +}); +scheme.PageOpenerParams = tOptional(tObject({})); +scheme.PageOpenerResult = tObject({ + page: tOptional(tChannel('Page')), +}); +scheme.PageReloadParams = tObject({ + timeout: tOptional(tNumber), + waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.PageReloadResult = tObject({ + response: tOptional(tChannel('Response')), +}); +scheme.PageScreenshotParams = tObject({ + timeout: tOptional(tNumber), + type: tOptional(tEnum(['png', 'jpeg'])), + path: tOptional(tString), + quality: tOptional(tNumber), + omitBackground: tOptional(tBoolean), + fullPage: tOptional(tBoolean), + clip: tOptional(tObject({ + width: tNumber, + height: tNumber, + x: tNumber, + y: tNumber, + })), +}); +scheme.PageScreenshotResult = tObject({ + binary: tBinary, +}); +scheme.PageSetExtraHTTPHeadersParams = tObject({ + headers: tArray(tObject({ + name: tString, + value: tString, + })), +}); +scheme.PageSetExtraHTTPHeadersResult = tUndefined; +scheme.PageSetNetworkInterceptionEnabledParams = tObject({ + enabled: tBoolean, +}); +scheme.PageSetNetworkInterceptionEnabledResult = tUndefined; +scheme.PageSetViewportSizeParams = tObject({ + viewportSize: tObject({ + width: tNumber, + height: tNumber, + }), +}); +scheme.PageSetViewportSizeResult = tUndefined; +scheme.PageKeyboardDownParams = tObject({ + key: tString, +}); +scheme.PageKeyboardDownResult = tUndefined; +scheme.PageKeyboardUpParams = tObject({ + key: tString, +}); +scheme.PageKeyboardUpResult = tUndefined; +scheme.PageKeyboardInsertTextParams = tObject({ + text: tString, +}); +scheme.PageKeyboardInsertTextResult = tUndefined; +scheme.PageKeyboardTypeParams = tObject({ + text: tString, + delay: tOptional(tNumber), +}); +scheme.PageKeyboardTypeResult = tUndefined; +scheme.PageKeyboardPressParams = tObject({ + key: tString, + delay: tOptional(tNumber), +}); +scheme.PageKeyboardPressResult = tUndefined; +scheme.PageMouseMoveParams = tObject({ + x: tNumber, + y: tNumber, + steps: tOptional(tNumber), +}); +scheme.PageMouseMoveResult = tUndefined; +scheme.PageMouseDownParams = tObject({ + button: tOptional(tEnum(['left', 'right', 'middle'])), + clickCount: tOptional(tNumber), +}); +scheme.PageMouseDownResult = tUndefined; +scheme.PageMouseUpParams = tObject({ + button: tOptional(tEnum(['left', 'right', 'middle'])), + clickCount: tOptional(tNumber), +}); +scheme.PageMouseUpResult = tUndefined; +scheme.PageMouseClickParams = tObject({ + x: tNumber, + y: tNumber, + delay: tOptional(tNumber), + button: tOptional(tEnum(['left', 'right', 'middle'])), + clickCount: tOptional(tNumber), +}); +scheme.PageMouseClickResult = tUndefined; +scheme.PageAccessibilitySnapshotParams = tObject({ + interestingOnly: tOptional(tBoolean), + root: tOptional(tChannel('ElementHandle')), +}); +scheme.PageAccessibilitySnapshotResult = tObject({ + rootAXNode: tOptional(tType('AXNode')), +}); +scheme.PagePdfParams = tObject({ + scale: tOptional(tNumber), + displayHeaderFooter: tOptional(tBoolean), + headerTemplate: tOptional(tString), + footerTemplate: tOptional(tString), + printBackground: tOptional(tBoolean), + landscape: tOptional(tBoolean), + pageRanges: tOptional(tString), + format: tOptional(tString), + width: tOptional(tString), + height: tOptional(tString), + preferCSSPageSize: tOptional(tBoolean), + margin: tOptional(tObject({ + top: tOptional(tString), + bottom: tOptional(tString), + left: tOptional(tString), + right: tOptional(tString), + })), +}); +scheme.PagePdfResult = tObject({ + pdf: tBinary, +}); +scheme.PageCrStartJSCoverageParams = tObject({ + resetOnNavigation: tOptional(tBoolean), + reportAnonymousScripts: tOptional(tBoolean), +}); +scheme.PageCrStartJSCoverageResult = tUndefined; +scheme.PageCrStopJSCoverageParams = tOptional(tObject({})); +scheme.PageCrStopJSCoverageResult = tObject({ + entries: tArray(tObject({ + url: tString, + scriptId: tString, + source: tOptional(tString), + functions: tArray(tObject({ + functionName: tString, + isBlockCoverage: tBoolean, + ranges: tArray(tObject({ + startOffset: tNumber, + endOffset: tNumber, + count: tNumber, + })), + })), + })), +}); +scheme.PageCrStartCSSCoverageParams = tObject({ + resetOnNavigation: tOptional(tBoolean), +}); +scheme.PageCrStartCSSCoverageResult = tUndefined; +scheme.PageCrStopCSSCoverageParams = tOptional(tObject({})); +scheme.PageCrStopCSSCoverageResult = tObject({ + entries: tArray(tObject({ + url: tString, + text: tOptional(tString), + ranges: tArray(tObject({ + start: tNumber, + end: tNumber, + })), + })), +}); +scheme.PageBringToFrontParams = tOptional(tObject({})); +scheme.PageBringToFrontResult = tUndefined; +scheme.FrameInitializer = tObject({ + url: tString, + name: tString, + parentFrame: tOptional(tChannel('Frame')), + loadStates: tArray(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.FrameLoadstateEvent = tObject({ + add: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + remove: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.FrameNavigatedEvent = tObject({ + url: tString, + name: tString, + newDocument: tOptional(tObject({ + request: tOptional(tChannel('Request')), + })), + error: tOptional(tString), +}); +scheme.FrameEvalOnSelectorParams = tObject({ + selector: tString, + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.FrameEvalOnSelectorResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.FrameEvalOnSelectorAllParams = tObject({ + selector: tString, + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.FrameEvalOnSelectorAllResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.FrameAddScriptTagParams = tObject({ + url: tOptional(tString), + content: tOptional(tString), + type: tOptional(tString), +}); +scheme.FrameAddScriptTagResult = tObject({ + element: tChannel('ElementHandle'), +}); +scheme.FrameAddStyleTagParams = tObject({ + url: tOptional(tString), + content: tOptional(tString), +}); +scheme.FrameAddStyleTagResult = tObject({ + element: tChannel('ElementHandle'), +}); +scheme.FrameCheckParams = tObject({ + selector: tString, + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.FrameCheckResult = tUndefined; +scheme.FrameClickParams = tObject({ + selector: tString, + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + delay: tOptional(tNumber), + button: tOptional(tEnum(['left', 'right', 'middle'])), + clickCount: tOptional(tNumber), + timeout: tOptional(tNumber), +}); +scheme.FrameClickResult = tUndefined; +scheme.FrameContentParams = tOptional(tObject({})); +scheme.FrameContentResult = tObject({ + value: tString, +}); +scheme.FrameDblclickParams = tObject({ + selector: tString, + force: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + delay: tOptional(tNumber), + button: tOptional(tEnum(['left', 'right', 'middle'])), + timeout: tOptional(tNumber), +}); +scheme.FrameDblclickResult = tUndefined; +scheme.FrameDispatchEventParams = tObject({ + selector: tString, + type: tString, + eventInit: tType('SerializedArgument'), + timeout: tOptional(tNumber), +}); +scheme.FrameDispatchEventResult = tUndefined; +scheme.FrameEvaluateExpressionParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.FrameEvaluateExpressionResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.FrameEvaluateExpressionHandleParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.FrameEvaluateExpressionHandleResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.FrameFillParams = tObject({ + selector: tString, + value: tString, + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.FrameFillResult = tUndefined; +scheme.FrameFocusParams = tObject({ + selector: tString, + timeout: tOptional(tNumber), +}); +scheme.FrameFocusResult = tUndefined; +scheme.FrameFrameElementParams = tOptional(tObject({})); +scheme.FrameFrameElementResult = tObject({ + element: tChannel('ElementHandle'), +}); +scheme.FrameGetAttributeParams = tObject({ + selector: tString, + name: tString, + timeout: tOptional(tNumber), +}); +scheme.FrameGetAttributeResult = tObject({ + value: tOptional(tString), +}); +scheme.FrameGotoParams = tObject({ + url: tString, + timeout: tOptional(tNumber), + waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), + referer: tOptional(tString), +}); +scheme.FrameGotoResult = tObject({ + response: tOptional(tChannel('Response')), +}); +scheme.FrameHoverParams = tObject({ + selector: tString, + force: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + timeout: tOptional(tNumber), +}); +scheme.FrameHoverResult = tUndefined; +scheme.FrameInnerHTMLParams = tObject({ + selector: tString, + timeout: tOptional(tNumber), +}); +scheme.FrameInnerHTMLResult = tObject({ + value: tString, +}); +scheme.FrameInnerTextParams = tObject({ + selector: tString, + timeout: tOptional(tNumber), +}); +scheme.FrameInnerTextResult = tObject({ + value: tString, +}); +scheme.FramePressParams = tObject({ + selector: tString, + key: tString, + delay: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.FramePressResult = tUndefined; +scheme.FrameQuerySelectorParams = tObject({ + selector: tString, +}); +scheme.FrameQuerySelectorResult = tObject({ + element: tOptional(tChannel('ElementHandle')), +}); +scheme.FrameQuerySelectorAllParams = tObject({ + selector: tString, +}); +scheme.FrameQuerySelectorAllResult = tObject({ + elements: tArray(tChannel('ElementHandle')), +}); +scheme.FrameSelectOptionParams = tObject({ + selector: tString, + elements: tOptional(tArray(tChannel('ElementHandle'))), + options: tOptional(tArray(tObject({ + value: tOptional(tString), + label: tOptional(tString), + index: tOptional(tNumber), + }))), + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.FrameSelectOptionResult = tObject({ + values: tArray(tString), +}); +scheme.FrameSetContentParams = tObject({ + html: tString, + timeout: tOptional(tNumber), + waitUntil: tOptional(tEnum(['load', 'domcontentloaded', 'networkidle'])), +}); +scheme.FrameSetContentResult = tUndefined; +scheme.FrameSetInputFilesParams = tObject({ + selector: tString, + files: tArray(tObject({ + name: tString, + mimeType: tString, + buffer: tString, + })), + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.FrameSetInputFilesResult = tUndefined; +scheme.FrameTextContentParams = tObject({ + selector: tString, + timeout: tOptional(tNumber), +}); +scheme.FrameTextContentResult = tObject({ + value: tOptional(tString), +}); +scheme.FrameTitleParams = tOptional(tObject({})); +scheme.FrameTitleResult = tObject({ + value: tString, +}); +scheme.FrameTypeParams = tObject({ + selector: tString, + text: tString, + delay: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.FrameTypeResult = tUndefined; +scheme.FrameUncheckParams = tObject({ + selector: tString, + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.FrameUncheckResult = tUndefined; +scheme.FrameWaitForFunctionParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), + timeout: tOptional(tNumber), + pollingInterval: tOptional(tNumber), +}); +scheme.FrameWaitForFunctionResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.FrameWaitForSelectorParams = tObject({ + selector: tString, + timeout: tOptional(tNumber), + state: tOptional(tEnum(['attached', 'detached', 'visible', 'hidden'])), +}); +scheme.FrameWaitForSelectorResult = tObject({ + element: tOptional(tChannel('ElementHandle')), +}); +scheme.WorkerInitializer = tObject({ + url: tString, +}); +scheme.WorkerEvaluateExpressionParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.WorkerEvaluateExpressionResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.WorkerEvaluateExpressionHandleParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.WorkerEvaluateExpressionHandleResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.JSHandleInitializer = tObject({ + preview: tString, +}); +scheme.JSHandlePreviewUpdatedEvent = tObject({ + preview: tString, +}); +scheme.ElementHandlePreviewUpdatedEvent = tType('JSHandlePreviewUpdatedEvent'); +scheme.JSHandleDisposeParams = tOptional(tObject({})); +scheme.JSHandleDisposeResult = tUndefined; +scheme.ElementHandleDisposeParams = tType('JSHandleDisposeParams'); +scheme.ElementHandleDisposeResult = tType('JSHandleDisposeResult'); +scheme.JSHandleEvaluateExpressionParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.JSHandleEvaluateExpressionResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.ElementHandleEvaluateExpressionParams = tType('JSHandleEvaluateExpressionParams'); +scheme.ElementHandleEvaluateExpressionResult = tType('JSHandleEvaluateExpressionResult'); +scheme.JSHandleEvaluateExpressionHandleParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.JSHandleEvaluateExpressionHandleResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.ElementHandleEvaluateExpressionHandleParams = tType('JSHandleEvaluateExpressionHandleParams'); +scheme.ElementHandleEvaluateExpressionHandleResult = tType('JSHandleEvaluateExpressionHandleResult'); +scheme.JSHandleGetPropertyListParams = tOptional(tObject({})); +scheme.JSHandleGetPropertyListResult = tObject({ + properties: tArray(tObject({ + name: tString, + value: tChannel('JSHandle'), + })), +}); +scheme.ElementHandleGetPropertyListParams = tType('JSHandleGetPropertyListParams'); +scheme.ElementHandleGetPropertyListResult = tType('JSHandleGetPropertyListResult'); +scheme.JSHandleGetPropertyParams = tObject({ + name: tString, +}); +scheme.JSHandleGetPropertyResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.ElementHandleGetPropertyParams = tType('JSHandleGetPropertyParams'); +scheme.ElementHandleGetPropertyResult = tType('JSHandleGetPropertyResult'); +scheme.JSHandleJsonValueParams = tOptional(tObject({})); +scheme.JSHandleJsonValueResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.ElementHandleJsonValueParams = tType('JSHandleJsonValueParams'); +scheme.ElementHandleJsonValueResult = tType('JSHandleJsonValueResult'); +scheme.ElementHandleInitializer = tObject({}); +scheme.ElementHandleEvalOnSelectorParams = tObject({ + selector: tString, + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.ElementHandleEvalOnSelectorResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.ElementHandleEvalOnSelectorAllParams = tObject({ + selector: tString, + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.ElementHandleEvalOnSelectorAllResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.ElementHandleBoundingBoxParams = tOptional(tObject({})); +scheme.ElementHandleBoundingBoxResult = tObject({ + value: tOptional(tObject({ + width: tNumber, + height: tNumber, + x: tNumber, + y: tNumber, + })), +}); +scheme.ElementHandleCheckParams = tObject({ + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleCheckResult = tUndefined; +scheme.ElementHandleClickParams = tObject({ + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + delay: tOptional(tNumber), + button: tOptional(tEnum(['left', 'right', 'middle'])), + clickCount: tOptional(tNumber), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleClickResult = tUndefined; +scheme.ElementHandleContentFrameParams = tOptional(tObject({})); +scheme.ElementHandleContentFrameResult = tObject({ + frame: tOptional(tChannel('Frame')), +}); +scheme.ElementHandleDblclickParams = tObject({ + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + delay: tOptional(tNumber), + button: tOptional(tEnum(['left', 'right', 'middle'])), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleDblclickResult = tUndefined; +scheme.ElementHandleDispatchEventParams = tObject({ + type: tString, + eventInit: tType('SerializedArgument'), +}); +scheme.ElementHandleDispatchEventResult = tUndefined; +scheme.ElementHandleFillParams = tObject({ + value: tString, + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.ElementHandleFillResult = tUndefined; +scheme.ElementHandleFocusParams = tOptional(tObject({})); +scheme.ElementHandleFocusResult = tUndefined; +scheme.ElementHandleGetAttributeParams = tObject({ + name: tString, +}); +scheme.ElementHandleGetAttributeResult = tObject({ + value: tOptional(tString), +}); +scheme.ElementHandleHoverParams = tObject({ + force: tOptional(tBoolean), + modifiers: tOptional(tArray(tEnum(['Alt', 'Control', 'Meta', 'Shift']))), + position: tOptional(tObject({ + x: tNumber, + y: tNumber, + })), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleHoverResult = tUndefined; +scheme.ElementHandleInnerHTMLParams = tOptional(tObject({})); +scheme.ElementHandleInnerHTMLResult = tObject({ + value: tString, +}); +scheme.ElementHandleInnerTextParams = tOptional(tObject({})); +scheme.ElementHandleInnerTextResult = tObject({ + value: tString, +}); +scheme.ElementHandleOwnerFrameParams = tOptional(tObject({})); +scheme.ElementHandleOwnerFrameResult = tObject({ + frame: tOptional(tChannel('Frame')), +}); +scheme.ElementHandlePressParams = tObject({ + key: tString, + delay: tOptional(tNumber), + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.ElementHandlePressResult = tUndefined; +scheme.ElementHandleQuerySelectorParams = tObject({ + selector: tString, +}); +scheme.ElementHandleQuerySelectorResult = tObject({ + element: tOptional(tChannel('ElementHandle')), +}); +scheme.ElementHandleQuerySelectorAllParams = tObject({ + selector: tString, +}); +scheme.ElementHandleQuerySelectorAllResult = tObject({ + elements: tArray(tChannel('ElementHandle')), +}); +scheme.ElementHandleScreenshotParams = tObject({ + timeout: tOptional(tNumber), + type: tOptional(tEnum(['png', 'jpeg'])), + path: tOptional(tString), + quality: tOptional(tNumber), + omitBackground: tOptional(tBoolean), +}); +scheme.ElementHandleScreenshotResult = tObject({ + binary: tBinary, +}); +scheme.ElementHandleScrollIntoViewIfNeededParams = tObject({ + timeout: tOptional(tNumber), +}); +scheme.ElementHandleScrollIntoViewIfNeededResult = tUndefined; +scheme.ElementHandleSelectOptionParams = tObject({ + elements: tOptional(tArray(tChannel('ElementHandle'))), + options: tOptional(tArray(tObject({ + value: tOptional(tString), + label: tOptional(tString), + index: tOptional(tNumber), + }))), + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.ElementHandleSelectOptionResult = tObject({ + values: tArray(tString), +}); +scheme.ElementHandleSelectTextParams = tObject({ + timeout: tOptional(tNumber), +}); +scheme.ElementHandleSelectTextResult = tUndefined; +scheme.ElementHandleSetInputFilesParams = tObject({ + files: tArray(tObject({ + name: tString, + mimeType: tString, + buffer: tString, + })), + timeout: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), +}); +scheme.ElementHandleSetInputFilesResult = tUndefined; +scheme.ElementHandleTextContentParams = tOptional(tObject({})); +scheme.ElementHandleTextContentResult = tObject({ + value: tOptional(tString), +}); +scheme.ElementHandleTypeParams = tObject({ + text: tString, + delay: tOptional(tNumber), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleTypeResult = tUndefined; +scheme.ElementHandleUncheckParams = tObject({ + force: tOptional(tBoolean), + noWaitAfter: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.ElementHandleUncheckResult = tUndefined; +scheme.RequestInitializer = tObject({ + frame: tChannel('Frame'), + url: tString, + resourceType: tString, + method: tString, + postData: tOptional(tBinary), + headers: tArray(tObject({ + name: tString, + value: tString, + })), + isNavigationRequest: tBoolean, + redirectedFrom: tOptional(tChannel('Request')), +}); +scheme.RequestResponseParams = tOptional(tObject({})); +scheme.RequestResponseResult = tObject({ + response: tOptional(tChannel('Response')), +}); +scheme.RouteInitializer = tObject({ + request: tChannel('Request'), +}); +scheme.RouteAbortParams = tObject({ + errorCode: tString, +}); +scheme.RouteAbortResult = tUndefined; +scheme.RouteContinueParams = tObject({ + method: tOptional(tString), + headers: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + postData: tOptional(tString), +}); +scheme.RouteContinueResult = tUndefined; +scheme.RouteFulfillParams = tObject({ + status: tNumber, + headers: tArray(tObject({ + name: tString, + value: tString, + })), + body: tString, + isBase64: tBoolean, +}); +scheme.RouteFulfillResult = tUndefined; +scheme.ResponseInitializer = tObject({ + request: tChannel('Request'), + url: tString, + status: tNumber, + statusText: tString, + headers: tArray(tObject({ + name: tString, + value: tString, + })), +}); +scheme.ResponseBodyParams = tOptional(tObject({})); +scheme.ResponseBodyResult = tObject({ + binary: tBinary, +}); +scheme.ResponseFinishedParams = tOptional(tObject({})); +scheme.ResponseFinishedResult = tObject({ + error: tOptional(tString), +}); +scheme.ConsoleMessageInitializer = tObject({ + type: tString, + text: tString, + args: tArray(tChannel('JSHandle')), + location: tObject({ + url: tOptional(tString), + lineNumber: tOptional(tNumber), + columnNumber: tOptional(tNumber), + }), +}); +scheme.BindingCallInitializer = tObject({ + frame: tChannel('Frame'), + name: tString, + args: tArray(tType('SerializedValue')), +}); +scheme.BindingCallRejectParams = tObject({ + error: tType('SerializedError'), +}); +scheme.BindingCallRejectResult = tUndefined; +scheme.BindingCallResolveParams = tObject({ + result: tType('SerializedArgument'), +}); +scheme.BindingCallResolveResult = tUndefined; +scheme.DialogInitializer = tObject({ + type: tString, + message: tString, + defaultValue: tString, +}); +scheme.DialogAcceptParams = tObject({ + promptText: tOptional(tString), +}); +scheme.DialogAcceptResult = tUndefined; +scheme.DialogDismissParams = tOptional(tObject({})); +scheme.DialogDismissResult = tUndefined; +scheme.DownloadInitializer = tObject({ + url: tString, + suggestedFilename: tString, +}); +scheme.DownloadPathParams = tOptional(tObject({})); +scheme.DownloadPathResult = tObject({ + value: tOptional(tString), +}); +scheme.DownloadSaveAsParams = tObject({ + path: tString, +}); +scheme.DownloadSaveAsResult = tUndefined; +scheme.DownloadFailureParams = tOptional(tObject({})); +scheme.DownloadFailureResult = tObject({ + error: tOptional(tString), +}); +scheme.DownloadStreamParams = tOptional(tObject({})); +scheme.DownloadStreamResult = tObject({ + stream: tOptional(tChannel('Stream')), +}); +scheme.DownloadDeleteParams = tOptional(tObject({})); +scheme.DownloadDeleteResult = tUndefined; +scheme.StreamInitializer = tObject({}); +scheme.StreamReadParams = tObject({ + size: tOptional(tNumber), +}); +scheme.StreamReadResult = tObject({ + binary: tBinary, +}); +scheme.CDPSessionInitializer = tObject({}); +scheme.CDPSessionEventEvent = tObject({ + method: tString, + params: tOptional(tType('SerializedValue')), +}); +scheme.CDPSessionDisconnectedEvent = tObject({}); +scheme.CDPSessionSendParams = tObject({ + method: tString, + params: tOptional(tType('SerializedValue')), +}); +scheme.CDPSessionSendResult = tObject({ + result: tType('SerializedValue'), +}); +scheme.CDPSessionDetachParams = tOptional(tObject({})); +scheme.CDPSessionDetachResult = tUndefined; +scheme.ElectronInitializer = tObject({}); +scheme.ElectronLaunchParams = tObject({ + executablePath: tString, + args: tOptional(tArray(tString)), + cwd: tOptional(tString), + env: tOptional(tArray(tObject({ + name: tString, + value: tString, + }))), + handleSIGINT: tOptional(tBoolean), + handleSIGTERM: tOptional(tBoolean), + handleSIGHUP: tOptional(tBoolean), + timeout: tOptional(tNumber), +}); +scheme.ElectronLaunchResult = tObject({ + electronApplication: tChannel('ElectronApplication'), +}); +scheme.ElectronApplicationInitializer = tObject({ + context: tChannel('BrowserContext'), +}); +scheme.ElectronApplicationCloseEvent = tObject({}); +scheme.ElectronApplicationWindowEvent = tObject({ + page: tChannel('Page'), + browserWindow: tChannel('JSHandle'), +}); +scheme.ElectronApplicationNewBrowserWindowParams = tObject({ + arg: tType('SerializedArgument'), +}); +scheme.ElectronApplicationNewBrowserWindowResult = tObject({ + page: tChannel('Page'), +}); +scheme.ElectronApplicationEvaluateExpressionParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.ElectronApplicationEvaluateExpressionResult = tObject({ + value: tType('SerializedValue'), +}); +scheme.ElectronApplicationEvaluateExpressionHandleParams = tObject({ + expression: tString, + isFunction: tBoolean, + arg: tType('SerializedArgument'), +}); +scheme.ElectronApplicationEvaluateExpressionHandleResult = tObject({ + handle: tChannel('JSHandle'), +}); +scheme.ElectronApplicationCloseParams = tOptional(tObject({})); +scheme.ElectronApplicationCloseResult = tUndefined; diff --git a/src/rpc/client/validatorPrimitives.ts b/src/rpc/client/validatorPrimitives.ts new file mode 100644 index 0000000000..722a9d436e --- /dev/null +++ b/src/rpc/client/validatorPrimitives.ts @@ -0,0 +1,123 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ChannelOwner } from './channelOwner'; +import { isUnderTest } from '../../helper'; + +class ValidationError extends Error {} + +export function validateParams(type: string, method: string, params: any): any { + const name = type + method[0].toUpperCase() + method.substring(1) + 'Params'; + if (!scheme[name]) + throw new ValidationError(`Uknown scheme for ${type}.${method}`); + return scheme[name](params, ''); +} + +type Validator = (arg: any, path: string) => any; + +export const tNumber: Validator = (arg: any, path: string) => { + if (arg instanceof Number) + return arg.valueOf(); + if (typeof arg === 'number') + return arg; + throw new ValidationError(`${path}: expected number, got ${typeof arg}`); +}; +export const tBoolean: Validator = (arg: any, path: string) => { + if (arg instanceof Boolean) + return arg.valueOf(); + if (typeof arg === 'boolean') + return arg; + throw new ValidationError(`${path}: expected boolean, got ${typeof arg}`); +}; +export const tString: Validator = (arg: any, path: string) => { + if (arg instanceof String) + return arg.valueOf(); + if (typeof arg === 'string') + return arg; + throw new ValidationError(`${path}: expected string, got ${typeof arg}`); +}; +export const tBinary: Validator = (arg: any, path: string) => { + // TODO: convert from Buffer here. + if (arg instanceof String) + return arg.valueOf(); + if (typeof arg === 'string') + return arg; + throw new ValidationError(`${path}: expected base64-encoded buffer, got ${typeof arg}`); +}; +export const tUndefined: Validator = (arg: any, path: string) => { + if (Object.is(arg, undefined)) + return arg; + throw new ValidationError(`${path}: expected undefined, got ${typeof arg}`); +}; +export const tOptional = (v: Validator): Validator => { + return (arg: any, path: string) => { + if (Object.is(arg, undefined)) + return arg; + return v(arg, path); + }; +}; +export const tArray = (v: Validator): Validator => { + return (arg: any, path: string) => { + if (!Array.isArray(arg)) + throw new ValidationError(`${path}: expected array, got ${typeof arg}`); + return arg.map((x, index) => v(x, path + '[' + index + ']')); + }; +}; +export const tObject = (s: { [key: string]: Validator }): Validator => { + return (arg: any, path: string) => { + if (Object.is(arg, null)) + throw new ValidationError(`${path}: expected object, got null`); + if (typeof arg !== 'object') + throw new ValidationError(`${path}: expected object, got ${typeof arg}`); + const result: any = {}; + for (const [key, v] of Object.entries(s)) { + const value = v(arg[key], path ? path + '.' + key : key); + if (!Object.is(value, undefined)) + result[key] = value; + } + if (isUnderTest()) { + for (const [key, value] of Object.entries(arg)) { + if (key.startsWith('__testHook')) + result[key] = value; + } + } + return result; + }; +}; +export const tEnum = (e: string[]): Validator => { + return (arg: any, path: string) => { + if (!e.includes(arg)) + throw new ValidationError(`${path}: expected one of (${e.join('|')})`); + return arg; + }; +}; +export const tChannel = (name: string): Validator => { + return (arg: any, path: string) => { + if (arg._object instanceof ChannelOwner && (name === '*' || arg._object._type === name)) + return { guid: arg._object._guid }; + throw new ValidationError(`${path}: expected ${name}`); + }; +}; +export const tType = (name: string): Validator => { + return (arg: any, path: string) => { + const v = scheme[name]; + if (!v) + throw new ValidationError(`${path}: unknown type "${name}"`); + return v(arg, path); + }; +}; + +export const scheme: { [key: string]: Validator } = {}; diff --git a/src/rpc/protocol.pdl b/src/rpc/protocol.pdl index 737a7a5136..281290d760 100644 --- a/src/rpc/protocol.pdl +++ b/src/rpc/protocol.pdl @@ -530,13 +530,13 @@ interface Page screen print # Reset emulated value to the system default. - reset + null colorScheme?: enum dark light no-preference # Reset emulated value to the system default. - reset + null command exposeBinding parameters diff --git a/src/rpc/server/pageDispatcher.ts b/src/rpc/server/pageDispatcher.ts index 4d711b0d72..cb282ad157 100644 --- a/src/rpc/server/pageDispatcher.ts +++ b/src/rpc/server/pageDispatcher.ts @@ -108,8 +108,8 @@ export class PageDispatcher extends Dispatcher implements async emulateMedia(params: PageEmulateMediaParams): Promise { await this._page.emulateMedia({ - media: params.media === 'reset' ? null : params.media, - colorScheme: params.colorScheme === 'reset' ? null : params.colorScheme, + media: params.media === 'null' ? null : params.media, + colorScheme: params.colorScheme === 'null' ? null : params.colorScheme, }); } diff --git a/test/emulation.jest.js b/test/emulation.jest.js index 75eebd8443..698d51492d 100644 --- a/test/emulation.jest.js +++ b/test/emulation.jest.js @@ -248,7 +248,7 @@ describe('Page.emulateMedia type', function() { it('should throw in case of bad type argument', async({page, server}) => { let error = null; await page.emulateMedia({ media: 'bad' }).catch(e => error = e); - expect(error.message).toContain('media: expected one of (screen|print)'); + expect(error.message).toContain('media: expected one of (screen|print|null)'); }); }); @@ -276,7 +276,7 @@ describe('Page.emulateMedia colorScheme', function() { it('should throw in case of bad argument', async({page, server}) => { let error = null; await page.emulateMedia({ colorScheme: 'bad' }).catch(e => error = e); - expect(error.message).toContain('colorScheme: expected one of (dark|light|no-preference)'); + expect(error.message).toContain('colorScheme: expected one of (dark|light|no-preference|null)'); }); it('should work during navigation', async({page, server}) => { await page.emulateMedia({ colorScheme: 'light' }); diff --git a/test/jest/fixtures.js b/test/jest/fixtures.js index 9233a2a753..ada40e88ef 100644 --- a/test/jest/fixtures.js +++ b/test/jest/fixtures.js @@ -24,6 +24,8 @@ const { Connection } = require('../../lib/rpc/client/connection'); const { Transport } = require('../../lib/rpc/transport'); const { PlaywrightDispatcher } = require('../../lib/rpc/server/playwrightDispatcher'); const { setUseApiName } = require('../../lib/progress'); +const { setUnderTest } = require('../../lib/helper'); +setUnderTest(); const browserName = process.env.BROWSER || 'chromium'; diff --git a/test/launcher.jest.js b/test/launcher.jest.js index 9e44dd8325..fbacd0f8c5 100644 --- a/test/launcher.jest.js +++ b/test/launcher.jest.js @@ -76,7 +76,7 @@ describe('Playwright', function() { const error = await browserType.launch(options).catch(e => e); expect(error.message).toContain(''); }); - it.skip(CHANNEL).slow()('should accept objects as options', async({browserType, defaultBrowserOptions}) => { + it.slow()('should accept objects as options', async({browserType, defaultBrowserOptions}) => { const browser = await browserType.launch({ ...defaultBrowserOptions, process }); await browser.close(); }); diff --git a/utils/generate_channels.js b/utils/generate_channels.js index c3d84a5cbd..329381b75e 100755 --- a/utils/generate_channels.js +++ b/utils/generate_channels.js @@ -72,8 +72,6 @@ function inlineType(item, indent) { inner = `{\n${properties(item, indent + ' ')}\n${indent}}`; } else if (type === 'binary') { inner = 'Binary'; - } else if (type === 'Error') { - inner = 'SerializedError'; } else if (channels.has(type)) { inner = type + 'Channel'; } else { @@ -82,6 +80,35 @@ function inlineType(item, indent) { return inner + (array ? '[]' : ''); } +function inlineTypeScheme(item, indent) { + let type = item.words[1]; + const array = type.endsWith('[]'); + if (array) + type = type.substring(0, type.length - 2); + let inner = ''; + if (type === 'enum') { + const literals = item.list.map(literal => { + if (literal.words.length > 1 || literal.list.length) + raise(literal); + return literal.words[0]; + }); + inner = `tEnum([${literals.map(literal => `'${literal}'`).join(', ')}])`; + } else if (['string', 'boolean', 'number', 'undefined'].includes(type)) { + inner = `t${titleCase(type)}`; + } else if (type === 'object') { + inner = `tObject({\n${propertiesScheme(item, indent + ' ')}\n${indent}})`; + } else if (type === 'binary') { + inner = 'tBinary'; + } else if (channels.has(type)) { + inner = `tChannel('${type}')`; + } else if (type === 'Channel') { + inner = `tChannel('*')`; + } else { + inner = `tType('${type}')`; + } + return array ? `tArray(${inner})` : inner; +} + function properties(item, indent) { const result = []; for (const prop of item.list) { @@ -99,13 +126,39 @@ function properties(item, indent) { return result.join('\n'); } +function propertiesScheme(item, indent) { + const result = []; + for (const prop of item.list) { + if (prop.words.length !== 2) + raise(prop); + let name = prop.words[0]; + if (!name.endsWith(':')) + raise(item); + name = name.substring(0, name.length - 1); + const optional = name.endsWith('?'); + if (optional) + name = name.substring(0, name.length - 1); + let type = inlineTypeScheme(prop, indent); + if (optional) + type = `tOptional(${type})`; + result.push(`${indent}${name}: ${type},`); + } + return result.join('\n'); +} + function objectType(name, item, indent) { if (!item.list.length) return `export type ${name} = {};`; return `export type ${name} = {\n${properties(item, indent)}\n};` } -const result = [ +function objectTypeScheme(item, indent) { + if (!item.list.length) + return `tObject({})`; + return `tObject({\n${propertiesScheme(item, indent)}\n})` +} + +const channels_ts = [ `/** * Copyright (c) Microsoft Corporation. * @@ -134,33 +187,46 @@ export interface Channel extends EventEmitter { const pdl = fs.readFileSync(path.join(__dirname, '..', 'src', 'rpc', 'protocol.pdl'), 'utf-8'); const list = tokenize(pdl); +const scheme = new Map(); +const inherits = new Map(); + +function addScheme(name, s) { + if (scheme.has(name)) + throw new Error('Duplicate scheme name ' + name); + scheme.set(name, s); +} for (const item of list) { - if (item.words[0] === 'interface') + if (item.words[0] === 'interface') { channels.add(item.words[1]); + if (item.words[2] === 'extends') + inherits.set(item.words[1], item.words[3]); + } } for (const item of list) { if (item.words[0] === 'type') { if (item.words.length !== 2) raise(item); - result.push(`export type ${item.words[1]} = {`); - result.push(properties(item, ' ')); - result.push(`};`); + channels_ts.push(`export type ${item.words[1]} = {`); + channels_ts.push(properties(item, ' ')); + channels_ts.push(`};`); + addScheme(item.words[1], objectTypeScheme(item, ' ')); } else if (item.words[0] === 'interface') { const channelName = item.words[1]; - result.push(`// ----------- ${channelName} -----------`); + channels_ts.push(`// ----------- ${channelName} -----------`); const init = item.list.find(i => i.words[0] === 'initializer'); if (init && init.words.length > 1) raise(init); - result.push(objectType(channelName + 'Initializer', init || { list: [] }, ' ')); + channels_ts.push(objectType(channelName + 'Initializer', init || { list: [] }, ' ')); + addScheme(channelName + 'Initializer', objectTypeScheme(init || { list: [] }, ' ')); let extendsName = 'Channel'; if (item.words.length === 4 && item.words[2] === 'extends') extendsName = item.words[3] + 'Channel'; else if (item.words.length !== 2) raise(item); - result.push(`export interface ${channelName}Channel extends ${extendsName} {`); + channels_ts.push(`export interface ${channelName}Channel extends ${extendsName} {`); const types = new Map(); for (const method of item.list) { @@ -174,12 +240,20 @@ for (const item of list) { const parameters = method.list.find(i => i.words[0] === 'parameters'); const paramsName = `${channelName}${titleCase(methodName)}Params`; types.set(paramsName, parameters || { list: [] }); + addScheme(paramsName, parameters ? objectTypeScheme(parameters, ' ') : `tOptional(tObject({}))`); const returns = method.list.find(i => i.words[0] === 'returns'); const resultName = `${channelName}${titleCase(methodName)}Result`; types.set(resultName, returns); + addScheme(resultName, returns ? objectTypeScheme(returns, ' ') : `tUndefined`); - result.push(` ${methodName}(params${parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`); + channels_ts.push(` ${methodName}(params${parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`); + for (const key of inherits.keys()) { + if (inherits.get(key) === channelName) { + addScheme(`${key}${titleCase(methodName)}Params`, `tType('${paramsName}')`); + addScheme(`${key}${titleCase(methodName)}Result`, `tType('${resultName}')`); + } + } } else if (method.words[0] === 'event') { if (method.words.length !== 2) raise(method); @@ -188,23 +262,56 @@ for (const item of list) { const parameters = method.list.find(i => i.words[0] === 'parameters'); const paramsName = `${channelName}${titleCase(eventName)}Event`; types.set(paramsName, parameters || { list: [] }); + addScheme(paramsName, objectTypeScheme(parameters || { list: [] }, ' ')); - result.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`); + channels_ts.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`); + for (const key of inherits.keys()) { + if (inherits.get(key) === channelName) + addScheme(`${key}${titleCase(eventName)}Event`, `tType('${paramsName}')`); + } } else { raise(method); } } - result.push(`}`); + channels_ts.push(`}`); for (const [name, item] of types) { if (!item) - result.push(`export type ${name} = void;`); + channels_ts.push(`export type ${name} = void;`); else - result.push(objectType(name, item, ' ')); + channels_ts.push(objectType(name, item, ' ')); } } else { raise(item); } - result.push(``); + channels_ts.push(``); } -fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), result.join('\n'), 'utf-8'); + +const client_validator_ts = [ +`/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file is generated by ${path.basename(__filename)}, do not edit manually. + +import { scheme, tOptional, tObject, tBoolean, tNumber, tString, tType, tEnum, tArray, tChannel, tUndefined, tBinary } from './validatorPrimitives'; +export { validateParams } from './validatorPrimitives'; +`]; +for (const [name, value] of scheme) + client_validator_ts.push(`scheme.${name} = ${value};`); +client_validator_ts.push(``); + +fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), channels_ts.join('\n'), 'utf-8'); +fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'client', 'validator.ts'), client_validator_ts.join('\n'), 'utf-8');