feat(rpc): introduce protocol.pdl (#3054)
We now generate channels.ts from the protocol definition. There are still some shortcomings, like union types - these will be addressed in follow ups.
This commit is contained in:
parent
726f636b5c
commit
5848ed8f41
1945
src/rpc/channels.ts
1945
src/rpc/channels.ts
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,6 @@ export class Accessibility {
|
|||
async snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<types.SerializedAXNode | null> {
|
||||
const root = options.root ? options.root._elementChannel : undefined;
|
||||
const result = await this._channel.accessibilitySnapshot({ interestingOnly: options.interestingOnly, root });
|
||||
return result.rootAXNode;
|
||||
return result.rootAXNode || null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { BrowserChannel, BrowserInitializer, BrowserContextOptions } from '../channels';
|
||||
import { BrowserChannel, BrowserInitializer, BrowserNewContextParams } from '../channels';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { Page } from './page';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
|
@ -55,7 +55,7 @@ export class Browser extends ChannelOwner<BrowserChannel, BrowserInitializer> {
|
|||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browser.newContext', async () => {
|
||||
const contextOptions: BrowserContextOptions = {
|
||||
const contextOptions: BrowserNewContextParams = {
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
|
||||
async setGeolocation(geolocation: types.Geolocation | null): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.setGeolocation', async () => {
|
||||
await this._channel.setGeolocation({ geolocation });
|
||||
await this._channel.setGeolocation({ geolocation: geolocation || undefined });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
|||
|
||||
async setHTTPCredentials(httpCredentials: types.Credentials | null): Promise<void> {
|
||||
return this._wrapApiCall('browserContext.setHTTPCredentials', async () => {
|
||||
await this._channel.setHTTPCredentials({ httpCredentials });
|
||||
await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || undefined });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { BrowserTypeChannel, BrowserTypeInitializer, LaunchPersistentContextOptions, LaunchOptions, LaunchServerOptions } from '../channels';
|
||||
import { BrowserTypeChannel, BrowserTypeInitializer, BrowserTypeLaunchParams, BrowserTypeLaunchServerParams, BrowserTypeLaunchPersistentContextParams } from '../channels';
|
||||
import { Browser } from './browser';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
|
@ -45,7 +45,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launch', async () => {
|
||||
const launchOptions: LaunchOptions = {
|
||||
const launchOptions: BrowserTypeLaunchParams = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
|
|
@ -61,7 +61,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launchServer', async () => {
|
||||
const launchServerOptions: LaunchServerOptions = {
|
||||
const launchServerOptions: BrowserTypeLaunchServerParams = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
|
|
@ -75,7 +75,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
|||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
|
||||
const persistentOptions: LaunchPersistentContextOptions = {
|
||||
const persistentOptions: BrowserTypeLaunchPersistentContextParams = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
|
|
|
|||
|
|
@ -37,11 +37,11 @@ export class Download extends ChannelOwner<DownloadChannel, DownloadInitializer>
|
|||
}
|
||||
|
||||
async path(): Promise<string | null> {
|
||||
return (await this._channel.path()).value;
|
||||
return (await this._channel.path()).value || null;
|
||||
}
|
||||
|
||||
async failure(): Promise<string | null> {
|
||||
return (await this._channel.failure()).error;
|
||||
return (await this._channel.failure()).error || null;
|
||||
}
|
||||
|
||||
async createReadStream(): Promise<Readable | null> {
|
||||
|
|
|
|||
|
|
@ -15,17 +15,18 @@
|
|||
*/
|
||||
|
||||
import * as types from '../../types';
|
||||
import { ElectronChannel, ElectronInitializer, ElectronLaunchOptions, ElectronApplicationChannel, ElectronApplicationInitializer } from '../channels';
|
||||
import { ElectronChannel, ElectronInitializer, ElectronApplicationChannel, ElectronApplicationInitializer, ElectronLaunchParams } from '../channels';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Page } from './page';
|
||||
import { serializeArgument, FuncOn, parseResult, SmartHandle, JSHandle } from './jsHandle';
|
||||
import { ElectronEvents } from '../../server/electron';
|
||||
import { ElectronEvents, ElectronLaunchOptionsBase } from '../../server/electron';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import { TimeoutError } from '../../errors';
|
||||
import { Events } from '../../events';
|
||||
import { LoggerSink } from '../../loggerSink';
|
||||
import { envObjectToArray } from '../serializers';
|
||||
|
||||
export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
|
||||
static from(electron: ElectronChannel): Electron {
|
||||
|
|
@ -36,11 +37,16 @@ export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer>
|
|||
super(parent, type, guid, initializer, true);
|
||||
}
|
||||
|
||||
async launch(executablePath: string, options: ElectronLaunchOptions & { logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
||||
async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
||||
const logger = options.logger;
|
||||
options = { ...options, logger: undefined };
|
||||
return this._wrapApiCall('electron.launch', async () => {
|
||||
return ElectronApplication.from((await this._channel.launch({ executablePath, ...options })).electronApplication);
|
||||
const params: ElectronLaunchParams = {
|
||||
...options,
|
||||
env: options.env ? envObjectToArray(options.env) : undefined,
|
||||
executablePath,
|
||||
};
|
||||
return ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||
}, logger);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
return (handle as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(handle: ElementHandleChannel | null): ElementHandle | null {
|
||||
static fromNullable(handle: ElementHandleChannel | undefined): ElementHandle | null {
|
||||
return handle ? ElementHandle.from(handle) : null;
|
||||
}
|
||||
|
||||
|
|
@ -56,13 +56,15 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
|
||||
async getAttribute(name: string): Promise<string | null> {
|
||||
return this._wrapApiCall('elementHandle.getAttribute', async () => {
|
||||
return (await this._elementChannel.getAttribute({ name })).value;
|
||||
const value = (await this._elementChannel.getAttribute({ name })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
async textContent(): Promise<string | null> {
|
||||
return this._wrapApiCall('elementHandle.textContent', async () => {
|
||||
return (await this._elementChannel.textContent()).value;
|
||||
const value = (await this._elementChannel.textContent()).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +167,8 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
|||
|
||||
async boundingBox(): Promise<types.Rect | null> {
|
||||
return this._wrapApiCall('elementHandle.boundingBox', async () => {
|
||||
return (await this._elementChannel.boundingBox()).value;
|
||||
const value = (await this._elementChannel.boundingBox()).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
return (frame as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(frame: FrameChannel | null): Frame | null {
|
||||
static fromNullable(frame: FrameChannel | undefined): Frame | null {
|
||||
return frame ? Frame.from(frame) : null;
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
});
|
||||
}
|
||||
|
||||
const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request || null) : null;
|
||||
const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request) : null;
|
||||
const response = request ? await waiter.waitForPromise(request._finalRequest().response()) : null;
|
||||
waiter.dispose();
|
||||
return response;
|
||||
|
|
@ -306,7 +306,8 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
|
||||
async textContent(selector: string, options: types.TimeoutOptions = {}): Promise<null|string> {
|
||||
return this._wrapApiCall(this._apiName('textContent'), async () => {
|
||||
return (await this._channel.textContent({ selector, ...options })).value;
|
||||
const value = (await this._channel.textContent({ selector, ...options })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +325,8 @@ export class Frame extends ChannelOwner<FrameChannel, FrameInitializer> {
|
|||
|
||||
async getAttribute(selector: string, name: string, options: types.TimeoutOptions = {}): Promise<string | null> {
|
||||
return this._wrapApiCall(this._apiName('getAttribute'), async () => {
|
||||
return (await this._channel.getAttribute({ selector, name, ...options })).value;
|
||||
const value = (await this._channel.getAttribute({ selector, name, ...options })).value;
|
||||
return value === undefined ? null : value;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { JSHandleChannel, JSHandleInitializer, SerializedArgument, Channel } from '../channels';
|
||||
import { JSHandleChannel, JSHandleInitializer, SerializedArgument, SerializedValue, Channel } from '../channels';
|
||||
import { ElementHandle } from './elementHandle';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { serializeAsCallArgument, parseEvaluationResultValue, SerializedValue } from '../../common/utilityScriptSerializers';
|
||||
import { serializeAsCallArgument, parseEvaluationResultValue } from '../../common/utilityScriptSerializers';
|
||||
|
||||
type NoHandles<Arg> = Arg extends JSHandle ? never : (Arg extends object ? { [Key in keyof Arg]: NoHandles<Arg[Key]> } : Arg);
|
||||
type Unboxed<Arg> =
|
||||
|
|
@ -42,10 +42,6 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
|
|||
return (handle as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(handle: JSHandleChannel | null): JSHandle | null {
|
||||
return handle ? JSHandle.from(handle) : null;
|
||||
}
|
||||
|
||||
constructor(parent: ChannelOwner, type: string, guid: string, initializer: JSHandleInitializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._preview = this._initializer.preview;
|
||||
|
|
@ -112,5 +108,5 @@ export function serializeArgument(arg: any): SerializedArgument {
|
|||
}
|
||||
|
||||
export function parseResult(arg: SerializedValue): any {
|
||||
return parseEvaluationResultValue(arg, []);
|
||||
return parseEvaluationResultValue(arg as any, []);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import * as types from '../../types';
|
|||
import { RequestChannel, ResponseChannel, RouteChannel, RequestInitializer, ResponseInitializer, RouteInitializer } from '../channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { Frame } from './frame';
|
||||
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides } from '../serializers';
|
||||
import { normalizeFulfillParameters, headersArrayToObject, normalizeContinueOverrides, parseError } from '../serializers';
|
||||
|
||||
export type NetworkCookie = {
|
||||
name: string,
|
||||
|
|
@ -54,7 +54,7 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
|
|||
return (request as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(request: RequestChannel | null): Request | null {
|
||||
static fromNullable(request: RequestChannel | undefined): Request | null {
|
||||
return request ? Request.from(request) : null;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ export class Request extends ChannelOwner<RequestChannel, RequestInitializer> {
|
|||
}
|
||||
|
||||
postData(): string | null {
|
||||
return this._initializer.postData;
|
||||
return this._initializer.postData || null;
|
||||
}
|
||||
|
||||
postDataJSON(): Object | null {
|
||||
|
|
@ -174,7 +174,7 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
|
|||
return (response as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(response: ResponseChannel | null): Response | null {
|
||||
static fromNullable(response: ResponseChannel | undefined): Response | null {
|
||||
return response ? Response.from(response) : null;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +204,10 @@ export class Response extends ChannelOwner<ResponseChannel, ResponseInitializer>
|
|||
}
|
||||
|
||||
async finished(): Promise<Error | null> {
|
||||
return (await this._channel.finished()).error;
|
||||
const result = await this._channel.finished();
|
||||
if (result.error)
|
||||
return parseError(result.error);
|
||||
return null;
|
||||
}
|
||||
|
||||
async body(): Promise<Buffer> {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import { Events } from '../../events';
|
|||
import { assert, assertMaxArguments, helper, Listener } from '../../helper';
|
||||
import { TimeoutSettings } from '../../timeoutSettings';
|
||||
import * as types from '../../types';
|
||||
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PDFOptions } from '../channels';
|
||||
import { parseError, serializeError, headersObjectToArray } from '../serializers';
|
||||
import { BindingCallChannel, BindingCallInitializer, PageChannel, PageInitializer, PagePdfParams } from '../channels';
|
||||
import { parseError, headersObjectToArray, serializeError } from '../serializers';
|
||||
import { Accessibility } from './accessibility';
|
||||
import { BrowserContext } from './browserContext';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
|
|
@ -69,7 +69,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
return (page as any)._object;
|
||||
}
|
||||
|
||||
static fromNullable(page: PageChannel | null): Page | null {
|
||||
static fromNullable(page: PageChannel | undefined): Page | null {
|
||||
return page ? Page.from(page) : null;
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
this._mainFrame = Frame.from(initializer.mainFrame);
|
||||
this._mainFrame._page = this;
|
||||
this._frames.add(this._mainFrame);
|
||||
this._viewportSize = initializer.viewportSize;
|
||||
this._viewportSize = initializer.viewportSize || null;
|
||||
this._closed = initializer.isClosed;
|
||||
|
||||
this._channel.on('bindingCall', ({ binding }) => this._onBinding(BindingCall.from(binding)));
|
||||
|
|
@ -115,8 +115,8 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
}
|
||||
}
|
||||
|
||||
private _onRequestFailed(request: Request, failureText: string | null) {
|
||||
request._failureText = failureText;
|
||||
private _onRequestFailed(request: Request, failureText: string | undefined) {
|
||||
request._failureText = failureText || null;
|
||||
this.emit(Events.Page.RequestFailed, request);
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +518,7 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
|||
|
||||
async _pdf(options: types.PDFOptions = {}): Promise<Buffer> {
|
||||
const path = options.path;
|
||||
const transportOptions: PDFOptions = { ...options } as PDFOptions;
|
||||
const transportOptions: PagePdfParams = { ...options } as PagePdfParams;
|
||||
if (path)
|
||||
delete (transportOptions as any).path;
|
||||
if (transportOptions.margin)
|
||||
|
|
|
|||
1483
src/rpc/protocol.pdl
Normal file
1483
src/rpc/protocol.pdl
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -21,24 +21,25 @@ import * as util from 'util';
|
|||
import { TimeoutError } from '../errors';
|
||||
import * as types from '../types';
|
||||
import { helper, assert } from '../helper';
|
||||
import { SerializedError } from './channels';
|
||||
import { serializeAsCallArgument, parseEvaluationResultValue } from '../common/utilityScriptSerializers';
|
||||
|
||||
|
||||
export function serializeError(e: any): types.Error {
|
||||
export function serializeError(e: any): SerializedError {
|
||||
if (helper.isError(e))
|
||||
return { message: e.message, stack: e.stack, name: e.name };
|
||||
return { value: e };
|
||||
return { error: { message: e.message, stack: e.stack, name: e.name } };
|
||||
return { value: serializeAsCallArgument(e, value => ({ fallThrough: value })) };
|
||||
}
|
||||
|
||||
export function parseError(error: types.Error): any {
|
||||
if (error.message === undefined)
|
||||
return error.value;
|
||||
if (error.name === 'TimeoutError') {
|
||||
const e = new TimeoutError(error.message);
|
||||
e.stack = error.stack;
|
||||
export function parseError(error: SerializedError): Error {
|
||||
if (!error.error)
|
||||
return parseEvaluationResultValue(error.value as any, []);
|
||||
if (error.error.name === 'TimeoutError') {
|
||||
const e = new TimeoutError(error.error.message);
|
||||
e.stack = error.error.stack || '';
|
||||
return e;
|
||||
}
|
||||
const e = new Error(error.message);
|
||||
e.stack = error.stack;
|
||||
const e = new Error(error.error.message);
|
||||
e.stack = error.error.stack || '';
|
||||
return e;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { BrowserContextBase, BrowserContext } from '../../browserContext';
|
|||
import { Events } from '../../events';
|
||||
import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher';
|
||||
import { PageDispatcher, BindingCallDispatcher, WorkerDispatcher } from './pageDispatcher';
|
||||
import { PageChannel, BrowserContextChannel, BrowserContextInitializer, CDPSessionChannel } from '../channels';
|
||||
import { PageChannel, BrowserContextChannel, BrowserContextInitializer, CDPSessionChannel, BrowserContextSetGeolocationParams, BrowserContextSetHTTPCredentialsParams } from '../channels';
|
||||
import { RouteDispatcher, RequestDispatcher } from './networkDispatchers';
|
||||
import { CRBrowserContext } from '../../chromium/crBrowser';
|
||||
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
|
||||
|
|
@ -91,8 +91,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
|
|||
await this._context.clearPermissions();
|
||||
}
|
||||
|
||||
async setGeolocation(params: { geolocation: types.Geolocation | null }): Promise<void> {
|
||||
await this._context.setGeolocation(params.geolocation);
|
||||
async setGeolocation(params: BrowserContextSetGeolocationParams): Promise<void> {
|
||||
await this._context.setGeolocation(params.geolocation || null);
|
||||
}
|
||||
|
||||
async setExtraHTTPHeaders(params: { headers: types.HeadersArray }): Promise<void> {
|
||||
|
|
@ -103,8 +103,8 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, Browser
|
|||
await this._context.setOffline(params.offline);
|
||||
}
|
||||
|
||||
async setHTTPCredentials(params: { httpCredentials: types.Credentials | null }): Promise<void> {
|
||||
await this._context.setHTTPCredentials(params.httpCredentials);
|
||||
async setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams): Promise<void> {
|
||||
await this._context.setHTTPCredentials(params.httpCredentials || null);
|
||||
}
|
||||
|
||||
async addInitScript(params: { source: string }): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
import { Browser, BrowserBase } from '../../browser';
|
||||
import { BrowserContextBase } from '../../browserContext';
|
||||
import { Events } from '../../events';
|
||||
import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel, Binary, BrowserContextOptions } from '../channels';
|
||||
import { BrowserChannel, BrowserContextChannel, BrowserInitializer, CDPSessionChannel, Binary, BrowserNewContextParams } from '../channels';
|
||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
|
||||
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||
|
|
@ -34,7 +34,7 @@ export class BrowserDispatcher extends Dispatcher<Browser, BrowserInitializer> i
|
|||
});
|
||||
}
|
||||
|
||||
async newContext(params: BrowserContextOptions): Promise<{ context: BrowserContextChannel }> {
|
||||
async newContext(params: BrowserNewContextParams): Promise<{ context: BrowserContextChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
extraHTTPHeaders: params.extraHTTPHeaders ? headersArrayToObject(params.extraHTTPHeaders) : undefined,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { BrowserBase } from '../../browser';
|
|||
import { BrowserTypeBase, BrowserType } from '../../server/browserType';
|
||||
import * as types from '../../types';
|
||||
import { BrowserDispatcher } from './browserDispatcher';
|
||||
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel, LaunchPersistentContextOptions, LaunchOptions, LaunchServerOptions } from '../channels';
|
||||
import { BrowserChannel, BrowserTypeChannel, BrowserContextChannel, BrowserTypeInitializer, BrowserServerChannel, BrowserTypeLaunchParams, BrowserTypeLaunchPersistentContextParams, BrowserTypeLaunchServerParams } from '../channels';
|
||||
import { Dispatcher, DispatcherScope } from './dispatcher';
|
||||
import { BrowserContextBase } from '../../browserContext';
|
||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||
|
|
@ -33,7 +33,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
|||
}, true, browserType.name());
|
||||
}
|
||||
|
||||
async launch(params: LaunchOptions): Promise<{ browser: BrowserChannel }> {
|
||||
async launch(params: BrowserTypeLaunchParams): Promise<{ browser: BrowserChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
|
||||
|
|
@ -43,7 +43,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
|||
return { browser: new BrowserDispatcher(this._scope, browser as BrowserBase) };
|
||||
}
|
||||
|
||||
async launchPersistentContext(params: LaunchPersistentContextOptions): Promise<{ context: BrowserContextChannel }> {
|
||||
async launchPersistentContext(params: BrowserTypeLaunchPersistentContextParams): Promise<{ context: BrowserContextChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
|
||||
|
|
@ -54,7 +54,7 @@ export class BrowserTypeDispatcher extends Dispatcher<BrowserType, BrowserTypeIn
|
|||
return { context: new BrowserContextDispatcher(this._scope, browserContext as BrowserContextBase) };
|
||||
}
|
||||
|
||||
async launchServer(params: LaunchServerOptions): Promise<{ server: BrowserServerChannel }> {
|
||||
async launchServer(params: BrowserTypeLaunchServerParams): Promise<{ server: BrowserServerChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
ignoreDefaultArgs: params.ignoreAllDefaultArgs ? true : params.ignoreDefaultArgs,
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ export function existingDispatcher<DispatcherType>(object: any): DispatcherType
|
|||
return object[dispatcherSymbol];
|
||||
}
|
||||
|
||||
export function lookupNullableDispatcher<DispatcherType>(object: any | null): DispatcherType | null {
|
||||
return object ? lookupDispatcher(object) : null;
|
||||
export function lookupNullableDispatcher<DispatcherType>(object: any | null): DispatcherType | undefined {
|
||||
return object ? lookupDispatcher(object) : undefined;
|
||||
}
|
||||
|
||||
export class Dispatcher<Type, Initializer> extends EventEmitter implements Channel {
|
||||
|
|
|
|||
|
|
@ -27,20 +27,22 @@ export class DownloadDispatcher extends Dispatcher<Download, DownloadInitializer
|
|||
});
|
||||
}
|
||||
|
||||
async path(): Promise<{ value: string | null }> {
|
||||
return { value: await this._object.path() };
|
||||
async path(): Promise<{ value?: string }> {
|
||||
const path = await this._object.path();
|
||||
return { value: path || undefined };
|
||||
}
|
||||
|
||||
async stream(): Promise<{ stream: StreamChannel | null }> {
|
||||
async stream(): Promise<{ stream?: StreamChannel }> {
|
||||
const stream = await this._object.createReadStream();
|
||||
if (!stream)
|
||||
return { stream: null };
|
||||
return {};
|
||||
await new Promise(f => stream.on('readable', f));
|
||||
return { stream: new StreamDispatcher(this._scope, stream) };
|
||||
}
|
||||
|
||||
async failure(): Promise<{ error: string | null }> {
|
||||
return { error: await this._object.failure() };
|
||||
async failure(): Promise<{ error?: string }> {
|
||||
const error = await this._object.failure();
|
||||
return { error: error || undefined };
|
||||
}
|
||||
|
||||
async delete(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -16,21 +16,26 @@
|
|||
|
||||
import { Dispatcher, DispatcherScope, lookupDispatcher } from './dispatcher';
|
||||
import { Electron, ElectronApplication, ElectronEvents, ElectronPage } from '../../server/electron';
|
||||
import { ElectronApplicationChannel, ElectronApplicationInitializer, PageChannel, JSHandleChannel, ElectronInitializer, ElectronChannel, ElectronLaunchOptions, SerializedArgument } from '../channels';
|
||||
import { ElectronApplicationChannel, ElectronApplicationInitializer, PageChannel, JSHandleChannel, ElectronInitializer, ElectronChannel, SerializedArgument, ElectronLaunchParams } from '../channels';
|
||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
|
||||
import { BrowserContextBase } from '../../browserContext';
|
||||
import { PageDispatcher } from './pageDispatcher';
|
||||
import { parseArgument, serializeResult } from './jsHandleDispatcher';
|
||||
import { createHandle } from './elementHandlerDispatcher';
|
||||
import { SerializedValue } from '../../common/utilityScriptSerializers';
|
||||
import { envArrayToObject } from '../serializers';
|
||||
|
||||
export class ElectronDispatcher extends Dispatcher<Electron, ElectronInitializer> implements ElectronChannel {
|
||||
constructor(scope: DispatcherScope, electron: Electron) {
|
||||
super(scope, electron, 'electron', {}, true);
|
||||
}
|
||||
|
||||
async launch(params: { executablePath: string } & ElectronLaunchOptions): Promise<{ electronApplication: ElectronApplicationChannel }> {
|
||||
const electronApplication = await this._object.launch(params.executablePath, params);
|
||||
async launch(params: ElectronLaunchParams): Promise<{ electronApplication: ElectronApplicationChannel }> {
|
||||
const options = {
|
||||
...params,
|
||||
env: params.env ? envArrayToObject(params.env) : undefined,
|
||||
};
|
||||
const electronApplication = await this._object.launch(params.executablePath, options);
|
||||
return { electronApplication: new ElectronApplicationDispatcher(this._scope, electronApplication) };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ export function createHandle(scope: DispatcherScope, handle: js.JSHandle): JSHan
|
|||
export class ElementHandleDispatcher extends JSHandleDispatcher implements ElementHandleChannel {
|
||||
readonly _elementHandle: ElementHandle;
|
||||
|
||||
static createNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | null {
|
||||
static createNullable(scope: DispatcherScope, handle: ElementHandle | null): ElementHandleDispatcher | undefined {
|
||||
if (!handle)
|
||||
return null;
|
||||
return undefined;
|
||||
return new ElementHandleDispatcher(scope, handle);
|
||||
}
|
||||
|
||||
|
|
@ -41,20 +41,22 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
|
|||
this._elementHandle = elementHandle;
|
||||
}
|
||||
|
||||
async ownerFrame(): Promise<{ frame: FrameChannel | null }> {
|
||||
async ownerFrame(): Promise<{ frame?: FrameChannel }> {
|
||||
return { frame: lookupNullableDispatcher<FrameDispatcher>(await this._elementHandle.ownerFrame()) };
|
||||
}
|
||||
|
||||
async contentFrame(): Promise<{ frame: FrameChannel | null }> {
|
||||
async contentFrame(): Promise<{ frame?: FrameChannel }> {
|
||||
return { frame: lookupNullableDispatcher<FrameDispatcher>(await this._elementHandle.contentFrame()) };
|
||||
}
|
||||
|
||||
async getAttribute(params: { name: string }): Promise<{ value: string | null }> {
|
||||
return { value: await this._elementHandle.getAttribute(params.name) };
|
||||
async getAttribute(params: { name: string }): Promise<{ value?: string }> {
|
||||
const value = await this._elementHandle.getAttribute(params.name);
|
||||
return { value: value === null ? undefined : value };
|
||||
}
|
||||
|
||||
async textContent(): Promise<{ value: string | null }> {
|
||||
return { value: await this._elementHandle.textContent() };
|
||||
async textContent(): Promise<{ value?: string }> {
|
||||
const value = await this._elementHandle.textContent();
|
||||
return { value: value === null ? undefined : value };
|
||||
}
|
||||
|
||||
async innerText(): Promise<{ value: string }> {
|
||||
|
|
@ -121,17 +123,18 @@ export class ElementHandleDispatcher extends JSHandleDispatcher implements Eleme
|
|||
await this._elementHandle.uncheck(params);
|
||||
}
|
||||
|
||||
async boundingBox(): Promise<{ value: types.Rect | null }> {
|
||||
return { value: await this._elementHandle.boundingBox() };
|
||||
async boundingBox(): Promise<{ value?: types.Rect }> {
|
||||
const value = await this._elementHandle.boundingBox();
|
||||
return { value: value || undefined };
|
||||
}
|
||||
|
||||
async screenshot(params: types.ElementScreenshotOptions): Promise<{ binary: Binary }> {
|
||||
return { binary: (await this._elementHandle.screenshot(params)).toString('base64') };
|
||||
}
|
||||
|
||||
async querySelector(params: { selector: string }): Promise<{ element: ElementHandleChannel | null }> {
|
||||
async querySelector(params: { selector: string }): Promise<{ element?: ElementHandleChannel }> {
|
||||
const handle = await this._elementHandle.$(params.selector);
|
||||
return { element: handle ? new ElementHandleDispatcher(this._scope, handle) : null };
|
||||
return { element: handle ? new ElementHandleDispatcher(this._scope, handle) : undefined };
|
||||
}
|
||||
|
||||
async querySelectorAll(params: { selector: string }): Promise<{ elements: ElementHandleChannel[] }> {
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
|||
});
|
||||
}
|
||||
|
||||
async goto(params: { url: string } & types.GotoOptions): Promise<{ response: ResponseChannel | null }> {
|
||||
async goto(params: { url: string } & types.GotoOptions): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._frame.goto(params.url, params)) };
|
||||
}
|
||||
|
||||
async waitForNavigation(params: types.WaitForNavigationOptions): Promise<{ response: ResponseChannel | null }> {
|
||||
async waitForNavigation(params: types.WaitForNavigationOptions): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._frame.waitForNavigation(params)) };
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
|||
return { handle: createHandle(this._scope, await this._frame._evaluateExpressionHandle(params.expression, params.isFunction, parseArgument(params.arg))) };
|
||||
}
|
||||
|
||||
async waitForSelector(params: { selector: string } & types.WaitForElementOptions): Promise<{ element: ElementHandleChannel | null }> {
|
||||
async waitForSelector(params: { selector: string } & types.WaitForElementOptions): Promise<{ element?: ElementHandleChannel }> {
|
||||
return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.waitForSelector(params.selector, params)) };
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
|||
return { value: serializeResult(await this._frame._$$evalExpression(params.selector, params.expression, params.isFunction, parseArgument(params.arg))) };
|
||||
}
|
||||
|
||||
async querySelector(params: { selector: string }): Promise<{ element: ElementHandleChannel | null }> {
|
||||
async querySelector(params: { selector: string }): Promise<{ element?: ElementHandleChannel }> {
|
||||
return { element: ElementHandleDispatcher.createNullable(this._scope, await this._frame.$(params.selector)) };
|
||||
}
|
||||
|
||||
|
|
@ -130,8 +130,9 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
|||
await this._frame.focus(params.selector, params);
|
||||
}
|
||||
|
||||
async textContent(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string | null }> {
|
||||
return { value: await this._frame.textContent(params.selector, params) };
|
||||
async textContent(params: { selector: string } & types.TimeoutOptions): Promise<{ value?: string }> {
|
||||
const value = await this._frame.textContent(params.selector, params);
|
||||
return { value: value === null ? undefined : value };
|
||||
}
|
||||
|
||||
async innerText(params: { selector: string } & types.TimeoutOptions): Promise<{ value: string }> {
|
||||
|
|
@ -142,8 +143,9 @@ export class FrameDispatcher extends Dispatcher<Frame, FrameInitializer> impleme
|
|||
return { value: await this._frame.innerHTML(params.selector, params) };
|
||||
}
|
||||
|
||||
async getAttribute(params: { selector: string, name: string } & types.TimeoutOptions): Promise<{ value: string | null }> {
|
||||
return { value: await this._frame.getAttribute(params.selector, params.name, params) };
|
||||
async getAttribute(params: { selector: string, name: string } & types.TimeoutOptions): Promise<{ value?: string }> {
|
||||
const value = await this._frame.getAttribute(params.selector, params.name, params);
|
||||
return { value: value === null ? undefined : value };
|
||||
}
|
||||
|
||||
async hover(params: { selector: string } & types.PointerActionOptions & types.TimeoutOptions & { force?: boolean }): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ export class JSHandleDispatcher extends Dispatcher<js.JSHandle, JSHandleInitiali
|
|||
// Generic channel parser converts guids to JSHandleDispatchers,
|
||||
// and this function takes care of coverting them into underlying JSHandles.
|
||||
export function parseArgument(arg: SerializedArgument): any {
|
||||
return parseEvaluationResultValue(arg.value, arg.handles.map(arg => (arg as JSHandleDispatcher)._object));
|
||||
return parseEvaluationResultValue(arg.value as any, arg.handles.map(arg => (arg as JSHandleDispatcher)._object));
|
||||
}
|
||||
|
||||
export function serializeResult(arg: any): SerializedValue {
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
|
||||
import { Request, Response, Route } from '../../network';
|
||||
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary } from '../channels';
|
||||
import { RequestChannel, ResponseChannel, RouteChannel, ResponseInitializer, RequestInitializer, RouteInitializer, Binary, SerializedError } from '../channels';
|
||||
import { Dispatcher, DispatcherScope, lookupNullableDispatcher, existingDispatcher } from './dispatcher';
|
||||
import { FrameDispatcher } from './frameDispatcher';
|
||||
import { headersObjectToArray, headersArrayToObject } from '../serializers';
|
||||
import { headersObjectToArray, headersArrayToObject, serializeError } from '../serializers';
|
||||
import * as types from '../../types';
|
||||
|
||||
export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> implements RequestChannel {
|
||||
|
|
@ -28,24 +28,25 @@ export class RequestDispatcher extends Dispatcher<Request, RequestInitializer> i
|
|||
return result || new RequestDispatcher(scope, request);
|
||||
}
|
||||
|
||||
static fromNullable(scope: DispatcherScope, request: Request | null): RequestDispatcher | null {
|
||||
return request ? RequestDispatcher.from(scope, request) : null;
|
||||
static fromNullable(scope: DispatcherScope, request: Request | null): RequestDispatcher | undefined {
|
||||
return request ? RequestDispatcher.from(scope, request) : undefined;
|
||||
}
|
||||
|
||||
private constructor(scope: DispatcherScope, request: Request) {
|
||||
const postData = request.postData();
|
||||
super(scope, request, 'request', {
|
||||
frame: FrameDispatcher.from(scope, request.frame()),
|
||||
url: request.url(),
|
||||
resourceType: request.resourceType(),
|
||||
method: request.method(),
|
||||
postData: request.postData(),
|
||||
postData: postData === null ? undefined : postData,
|
||||
headers: headersObjectToArray(request.headers()),
|
||||
isNavigationRequest: request.isNavigationRequest(),
|
||||
redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom()),
|
||||
});
|
||||
}
|
||||
|
||||
async response(): Promise<{ response: ResponseChannel | null }> {
|
||||
async response(): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._object.response()) };
|
||||
}
|
||||
}
|
||||
|
|
@ -63,8 +64,9 @@ export class ResponseDispatcher extends Dispatcher<Response, ResponseInitializer
|
|||
});
|
||||
}
|
||||
|
||||
async finished(): Promise<{ error: Error | null }> {
|
||||
return { error: await this._object.finished() };
|
||||
async finished(): Promise<{ error?: SerializedError }> {
|
||||
const error = await this._object.finished();
|
||||
return { error: error ? serializeError(error) : undefined };
|
||||
}
|
||||
|
||||
async body(): Promise<{ binary: Binary }> {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { Frame } from '../../frames';
|
|||
import { Request } from '../../network';
|
||||
import { Page, Worker } from '../../page';
|
||||
import * as types from '../../types';
|
||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, PDFOptions, SerializedArgument } from '../channels';
|
||||
import { BindingCallChannel, BindingCallInitializer, ElementHandleChannel, PageChannel, PageInitializer, ResponseChannel, WorkerInitializer, WorkerChannel, JSHandleChannel, Binary, SerializedArgument, PagePdfParams, SerializedError } from '../channels';
|
||||
import { Dispatcher, DispatcherScope, lookupDispatcher, lookupNullableDispatcher } from './dispatcher';
|
||||
import { parseError, serializeError, headersArrayToObject } from '../serializers';
|
||||
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
|
||||
|
|
@ -42,7 +42,7 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
|||
// If we split pageCreated and pageReady, there should be no main frame during pageCreated.
|
||||
super(scope, page, 'page', {
|
||||
mainFrame: FrameDispatcher.from(scope, page.mainFrame()),
|
||||
viewportSize: page.viewportSize(),
|
||||
viewportSize: page.viewportSize() || undefined,
|
||||
isClosed: page.isClosed()
|
||||
});
|
||||
this._page = page;
|
||||
|
|
@ -79,7 +79,7 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
|||
this._page.setDefaultTimeout(params.timeout);
|
||||
}
|
||||
|
||||
async opener(): Promise<{ page: PageChannel | null }> {
|
||||
async opener(): Promise<{ page?: PageChannel }> {
|
||||
return { page: lookupNullableDispatcher<PageDispatcher>(await this._page.opener()) };
|
||||
}
|
||||
|
||||
|
|
@ -95,15 +95,15 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
|||
await this._page.setExtraHTTPHeaders(headersArrayToObject(params.headers));
|
||||
}
|
||||
|
||||
async reload(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> {
|
||||
async reload(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._page.reload(params)) };
|
||||
}
|
||||
|
||||
async goBack(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> {
|
||||
async goBack(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._page.goBack(params)) };
|
||||
}
|
||||
|
||||
async goForward(params: types.NavigateOptions): Promise<{ response: ResponseChannel | null }> {
|
||||
async goForward(params: types.NavigateOptions): Promise<{ response?: ResponseChannel }> {
|
||||
return { response: lookupNullableDispatcher<ResponseDispatcher>(await this._page.goForward(params)) };
|
||||
}
|
||||
|
||||
|
|
@ -180,15 +180,15 @@ export class PageDispatcher extends Dispatcher<Page, PageInitializer> implements
|
|||
await this._page.mouse.click(params.x, params.y, params);
|
||||
}
|
||||
|
||||
async accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<{ rootAXNode: types.SerializedAXNode | null }> {
|
||||
async accessibilitySnapshot(params: { interestingOnly?: boolean, root?: ElementHandleChannel }): Promise<{ rootAXNode?: types.SerializedAXNode }> {
|
||||
const rootAXNode = await this._page.accessibility.snapshot({
|
||||
interestingOnly: params.interestingOnly,
|
||||
root: params.root ? (params.root as ElementHandleDispatcher)._elementHandle : undefined
|
||||
});
|
||||
return { rootAXNode };
|
||||
return { rootAXNode: rootAXNode || undefined };
|
||||
}
|
||||
|
||||
async pdf(params: PDFOptions): Promise<{ pdf: Binary }> {
|
||||
async pdf(params: PagePdfParams): Promise<{ pdf: Binary }> {
|
||||
if (!this._page.pdf)
|
||||
throw new Error('PDF generation is only supported for Headless Chromium');
|
||||
const buffer = await this._page.pdf(params);
|
||||
|
|
@ -263,11 +263,11 @@ export class BindingCallDispatcher extends Dispatcher<{}, BindingCallInitializer
|
|||
return this._promise;
|
||||
}
|
||||
|
||||
resolve(params: { result: SerializedArgument }) {
|
||||
async resolve(params: { result: SerializedArgument }) {
|
||||
this._resolve!(parseArgument(params.result));
|
||||
}
|
||||
|
||||
reject(params: { error: types.Error }) {
|
||||
async reject(params: { error: SerializedError }) {
|
||||
this._reject!(parseError(params.error));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,15 +34,14 @@ import { EventEmitter } from 'events';
|
|||
import { helper } from '../helper';
|
||||
import { LoggerSink } from '../loggerSink';
|
||||
|
||||
type ElectronLaunchOptions = {
|
||||
export type ElectronLaunchOptionsBase = {
|
||||
args?: string[],
|
||||
cwd?: string,
|
||||
env?: {[key: string]: string|number|boolean},
|
||||
env?: types.Env,
|
||||
handleSIGINT?: boolean,
|
||||
handleSIGTERM?: boolean,
|
||||
handleSIGHUP?: boolean,
|
||||
timeout?: number,
|
||||
logger?: LoggerSink,
|
||||
};
|
||||
|
||||
export const ElectronEvents = {
|
||||
|
|
@ -165,7 +164,7 @@ export class ElectronApplication extends EventEmitter {
|
|||
}
|
||||
|
||||
export class Electron {
|
||||
async launch(executablePath: string, options: ElectronLaunchOptions = {}): Promise<ElectronApplication> {
|
||||
async launch(executablePath: string, options: ElectronLaunchOptionsBase & { logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
||||
const {
|
||||
args = [],
|
||||
env = process.env,
|
||||
|
|
|
|||
|
|
@ -348,8 +348,7 @@ export type ConsoleMessageLocation = {
|
|||
};
|
||||
|
||||
export type Error = {
|
||||
message?: string,
|
||||
name?: string,
|
||||
message: string,
|
||||
name: string,
|
||||
stack?: string,
|
||||
value?: any
|
||||
};
|
||||
|
|
|
|||
217
utils/generate_channels.js
Executable file
217
utils/generate_channels.js
Executable file
|
|
@ -0,0 +1,217 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const channels = new Set();
|
||||
|
||||
function tokenize(source) {
|
||||
const lines = source.split('\n').filter(line => {
|
||||
const trimmed = line.trim();
|
||||
return !!trimmed && trimmed[0] != '#';
|
||||
});
|
||||
|
||||
const stack = [{ indent: -1, list: [], words: '' }];
|
||||
for (const line of lines) {
|
||||
const indent = line.length - line.trimLeft().length;
|
||||
const o = { indent, list: [], words: line.split(' ').filter(word => !!word) };
|
||||
|
||||
let current = stack[stack.length - 1];
|
||||
while (indent <= current.indent) {
|
||||
stack.pop();
|
||||
current = stack[stack.length - 1];
|
||||
}
|
||||
|
||||
current.list.push(o);
|
||||
stack.push(o);
|
||||
}
|
||||
return stack[0].list;
|
||||
}
|
||||
|
||||
function raise(item) {
|
||||
throw new Error(item.words.join(' '));
|
||||
}
|
||||
|
||||
function titleCase(name) {
|
||||
return name[0].toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
function inlineType(type, item, indent) {
|
||||
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 = literals.map(literal => `'${literal}'`).join(' | ');
|
||||
if (array)
|
||||
inner = `(${inner})`;
|
||||
} else if (['string', 'boolean', 'number', 'undefined'].includes(type)) {
|
||||
inner = type;
|
||||
} else if (type === 'object') {
|
||||
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 {
|
||||
inner = type;
|
||||
}
|
||||
return inner + (array ? '[]' : '');
|
||||
}
|
||||
|
||||
function properties(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);
|
||||
result.push(`${indent}${name}${optional ? '?' : ''}: ${inlineType(prop.words[1], prop, indent)},`);
|
||||
}
|
||||
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 = [
|
||||
`/**
|
||||
* 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 { EventEmitter } from 'events';
|
||||
|
||||
export type Binary = string;
|
||||
|
||||
export interface Channel extends EventEmitter {
|
||||
}
|
||||
`];
|
||||
|
||||
const pdl = fs.readFileSync(path.join(__dirname, '..', 'src', 'rpc', 'protocol.pdl'), 'utf-8');
|
||||
const list = tokenize(pdl);
|
||||
|
||||
for (const item of list) {
|
||||
if (item.words[0] === 'interface')
|
||||
channels.add(item.words[1]);
|
||||
}
|
||||
|
||||
for (const item of list) {
|
||||
if (item.words[0] === 'union') {
|
||||
if (item.words.length !== 2)
|
||||
raise(item);
|
||||
result.push(`export type ${item.words[1]} = ${item.list.map(clause => {
|
||||
if (clause.words.length !== 1)
|
||||
raise(clause);
|
||||
return inlineType(clause.words[0], clause, ' ');
|
||||
}).join(' | ')};`);
|
||||
} else 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(`};`);
|
||||
} else if (item.words[0] === 'interface') {
|
||||
const channelName = item.words[1];
|
||||
result.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: [] }, ' '));
|
||||
|
||||
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} {`);
|
||||
|
||||
const types = new Map();
|
||||
for (const method of item.list) {
|
||||
if (method === init)
|
||||
continue;
|
||||
if (method.words[0] === 'command') {
|
||||
if (method.words.length !== 2)
|
||||
raise(method);
|
||||
const methodName = method.words[1];
|
||||
|
||||
const parameters = method.list.find(i => i.words[0] === 'parameters');
|
||||
const paramsName = `${channelName}${titleCase(methodName)}Params`;
|
||||
types.set(paramsName, parameters || { list: [] });
|
||||
|
||||
const returns = method.list.find(i => i.words[0] === 'returns');
|
||||
const resultName = `${channelName}${titleCase(methodName)}Result`;
|
||||
types.set(resultName, returns);
|
||||
|
||||
result.push(` ${methodName}(params${parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`);
|
||||
} else if (method.words[0] === 'event') {
|
||||
if (method.words.length !== 2)
|
||||
raise(method);
|
||||
const eventName = method.words[1];
|
||||
|
||||
const parameters = method.list.find(i => i.words[0] === 'parameters');
|
||||
const paramsName = `${channelName}${titleCase(eventName)}Event`;
|
||||
types.set(paramsName, parameters || { list: [] });
|
||||
|
||||
result.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`);
|
||||
} else {
|
||||
raise(method);
|
||||
}
|
||||
}
|
||||
result.push(`}`);
|
||||
for (const [name, item] of types) {
|
||||
if (!item)
|
||||
result.push(`export type ${name} = void;`);
|
||||
else
|
||||
result.push(objectType(name, item, ' '));
|
||||
}
|
||||
} else {
|
||||
raise(item);
|
||||
}
|
||||
result.push(``);
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), result.join('\n'), 'utf-8');
|
||||
Loading…
Reference in a new issue