feat(rpc): run doclint against rpc client (#3260)
This commit is contained in:
parent
f62e9b5dc0
commit
126b1f79d4
|
|
@ -17,8 +17,9 @@
|
||||||
"tsc": "tsc -p .",
|
"tsc": "tsc -p .",
|
||||||
"tsc-installer": "tsc -p ./src/install/tsconfig.json",
|
"tsc-installer": "tsc -p ./src/install/tsconfig.json",
|
||||||
"doc": "node utils/doclint/cli.js",
|
"doc": "node utils/doclint/cli.js",
|
||||||
|
"doc-channel": "node utils/doclint/cli.js --channel",
|
||||||
"test-infra": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js && node utils/testrunner/test/test.js",
|
"test-infra": "node utils/doclint/check_public_api/test/test.js && node utils/doclint/preprocessor/test.js && node utils/testrunner/test/test.js",
|
||||||
"lint": "npm run eslint && npm run tsc && npm run doc && npm run check-deps && npm run generate-channels && npm run test-types && npm run test-infra",
|
"lint": "npm run eslint && npm run tsc && npm run doc && npm run doc-channel && npm run check-deps && npm run generate-channels && npm run test-types && npm run test-infra",
|
||||||
"debug-test": "node --inspect-brk test/test.js",
|
"debug-test": "node --inspect-brk test/test.js",
|
||||||
"clean": "rimraf lib && rimraf types",
|
"clean": "rimraf lib && rimraf types",
|
||||||
"prepare": "node install-from-github.js",
|
"prepare": "node install-from-github.js",
|
||||||
|
|
|
||||||
44
src/rpc/client/api.ts
Normal file
44
src/rpc/client/api.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { Accessibility } from './accessibility';
|
||||||
|
export { Browser } from './browser';
|
||||||
|
export { BrowserContext } from './browserContext';
|
||||||
|
export { BrowserServer } from './browserServer';
|
||||||
|
export { BrowserType } from './browserType';
|
||||||
|
export { ConsoleMessage } from './consoleMessage';
|
||||||
|
export { Dialog } from './dialog';
|
||||||
|
export { Download } from './download';
|
||||||
|
export { ElementHandle } from './elementHandle';
|
||||||
|
export { FileChooser } from './fileChooser';
|
||||||
|
export { Logger } from '../../loggerSink';
|
||||||
|
export { TimeoutError } from '../../errors';
|
||||||
|
export { Frame } from './frame';
|
||||||
|
export { Keyboard, Mouse } from './input';
|
||||||
|
export { JSHandle } from './jsHandle';
|
||||||
|
export { Request, Response, Route } from './network';
|
||||||
|
export { Page } from './page';
|
||||||
|
export { Selectors } from './selectors';
|
||||||
|
export { Worker } from './worker';
|
||||||
|
|
||||||
|
export { ChromiumBrowser } from './chromiumBrowser';
|
||||||
|
export { ChromiumBrowserContext } from './chromiumBrowserContext';
|
||||||
|
export { ChromiumCoverage } from './chromiumCoverage';
|
||||||
|
export { CDPSession } from './cdpSession';
|
||||||
|
|
||||||
|
export { WebKitBrowser } from './webkitBrowser';
|
||||||
|
|
||||||
|
export { FirefoxBrowser } from './firefoxBrowser';
|
||||||
|
|
@ -169,7 +169,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async exposeBinding(name: string, binding: frames.FunctionWithSource): Promise<void> {
|
async exposeBinding(name: string, playwrightBinding: frames.FunctionWithSource): Promise<void> {
|
||||||
return this._wrapApiCall('browserContext.exposeBinding', async () => {
|
return this._wrapApiCall('browserContext.exposeBinding', async () => {
|
||||||
for (const page of this.pages()) {
|
for (const page of this.pages()) {
|
||||||
if (page._bindings.has(name))
|
if (page._bindings.has(name))
|
||||||
|
|
@ -177,7 +177,7 @@ export class BrowserContext extends ChannelOwner<BrowserContextChannel, BrowserC
|
||||||
}
|
}
|
||||||
if (this._bindings.has(name))
|
if (this._bindings.has(name))
|
||||||
throw new Error(`Function "${name}" has been already registered`);
|
throw new Error(`Function "${name}" has been already registered`);
|
||||||
this._bindings.set(name, binding);
|
this._bindings.set(name, playwrightBinding);
|
||||||
await this._channel.exposeBinding({ name });
|
await this._channel.exposeBinding({ name });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import { BrowserServer } from './browserServer';
|
||||||
import { headersObjectToArray, envObjectToArray } from '../../converters';
|
import { headersObjectToArray, envObjectToArray } from '../../converters';
|
||||||
import { serializeArgument } from './jsHandle';
|
import { serializeArgument } from './jsHandle';
|
||||||
import { assert } from '../../helper';
|
import { assert } from '../../helper';
|
||||||
import { LaunchOptions, LaunchServerOptions, BrowserContextOptions, ConnectOptions } from './types';
|
import { LaunchOptions, LaunchServerOptions, ConnectOptions, LaunchPersistentContextOptions } from './types';
|
||||||
|
|
||||||
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeInitializer> {
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ export class BrowserType extends ChannelOwner<BrowserTypeChannel, BrowserTypeIni
|
||||||
}, logger);
|
}, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
async launchPersistentContext(userDataDir: string, options: LaunchOptions & BrowserContextOptions = {}): Promise<BrowserContext> {
|
async launchPersistentContext(userDataDir: string, options: LaunchPersistentContextOptions = {}): Promise<BrowserContext> {
|
||||||
const logger = options.logger;
|
const logger = options.logger;
|
||||||
options = { ...options, logger: undefined };
|
options = { ...options, logger: undefined };
|
||||||
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
|
return this._wrapApiCall('browserType.launchPersistentContext', async () => {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,11 @@ import { Events } from './events';
|
||||||
import { envObjectToArray } from '../../converters';
|
import { envObjectToArray } from '../../converters';
|
||||||
import { WaitForEventOptions, Env, LoggerSink } from './types';
|
import { WaitForEventOptions, Env, LoggerSink } from './types';
|
||||||
|
|
||||||
|
type ElectronOptions = Omit<ElectronLaunchOptions, 'env'> & {
|
||||||
|
env?: Env,
|
||||||
|
logger?: LoggerSink,
|
||||||
|
};
|
||||||
|
|
||||||
export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
|
export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer> {
|
||||||
static from(electron: ElectronChannel): Electron {
|
static from(electron: ElectronChannel): Electron {
|
||||||
return (electron as any)._object;
|
return (electron as any)._object;
|
||||||
|
|
@ -34,7 +39,7 @@ export class Electron extends ChannelOwner<ElectronChannel, ElectronInitializer>
|
||||||
super(parent, type, guid, initializer);
|
super(parent, type, guid, initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async launch(executablePath: string, options: ElectronLaunchOptions & { env?: Env, logger?: LoggerSink } = {}): Promise<ElectronApplication> {
|
async launch(executablePath: string, options: ElectronOptions = {}): Promise<ElectronApplication> {
|
||||||
const logger = options.logger;
|
const logger = options.logger;
|
||||||
options = { ...options, logger: undefined };
|
options = { ...options, logger: undefined };
|
||||||
return this._wrapApiCall('electron.launch', async () => {
|
return this._wrapApiCall('electron.launch', async () => {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ElementHandleChannel, JSHandleInitializer, ElementHandleScrollIntoViewIfNeededOptions, ElementHandleHoverOptions, ElementHandleClickOptions, ElementHandleDblclickOptions, ElementHandleSelectOptionOptions, ElementHandleFillOptions, ElementHandleSetInputFilesOptions, ElementHandlePressOptions, ElementHandleCheckOptions, ElementHandleUncheckOptions, ElementHandleScreenshotOptions, ElementHandleTypeOptions } from '../channels';
|
import { ElementHandleChannel, JSHandleInitializer, ElementHandleScrollIntoViewIfNeededOptions, ElementHandleHoverOptions, ElementHandleClickOptions, ElementHandleDblclickOptions, ElementHandleFillOptions, ElementHandleSetInputFilesOptions, ElementHandlePressOptions, ElementHandleCheckOptions, ElementHandleUncheckOptions, ElementHandleScreenshotOptions, ElementHandleTypeOptions, ElementHandleSelectTextOptions } from '../channels';
|
||||||
import { Frame } from './frame';
|
import { Frame } from './frame';
|
||||||
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
import { FuncOn, JSHandle, serializeArgument, parseResult } from './jsHandle';
|
||||||
import { ChannelOwner } from './channelOwner';
|
import { ChannelOwner } from './channelOwner';
|
||||||
|
|
@ -123,7 +123,7 @@ export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectText(options: ElementHandleSelectOptionOptions = {}): Promise<void> {
|
async selectText(options: ElementHandleSelectTextOptions = {}): Promise<void> {
|
||||||
return this._wrapApiCall('elementHandle.selectText', async () => {
|
return this._wrapApiCall('elementHandle.selectText', async () => {
|
||||||
await this._elementChannel.selectText(options);
|
await this._elementChannel.selectText(options);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ export class JSHandle<T = any> extends ChannelOwner<JSHandleChannel, JSHandleIni
|
||||||
return JSHandle.from(result.handle) as SmartHandle<R>;
|
return JSHandle.from(result.handle) as SmartHandle<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProperty(name: string): Promise<JSHandle> {
|
async getProperty(propertyName: string): Promise<JSHandle> {
|
||||||
const result = await this._channel.getProperty({ name });
|
const result = await this._channel.getProperty({ name: propertyName });
|
||||||
return JSHandle.from(result.handle);
|
return JSHandle.from(result.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -278,13 +278,13 @@ export class Page extends ChannelOwner<PageChannel, PageInitializer> {
|
||||||
await this.exposeBinding(name, (options, ...args: any) => playwrightFunction(...args));
|
await this.exposeBinding(name, (options, ...args: any) => playwrightFunction(...args));
|
||||||
}
|
}
|
||||||
|
|
||||||
async exposeBinding(name: string, binding: FunctionWithSource) {
|
async exposeBinding(name: string, playwrightBinding: FunctionWithSource) {
|
||||||
return this._wrapApiCall('page.exposeBinding', async () => {
|
return this._wrapApiCall('page.exposeBinding', async () => {
|
||||||
if (this._bindings.has(name))
|
if (this._bindings.has(name))
|
||||||
throw new Error(`Function "${name}" has been already registered`);
|
throw new Error(`Function "${name}" has been already registered`);
|
||||||
if (this._browserContext._bindings.has(name))
|
if (this._browserContext._bindings.has(name))
|
||||||
throw new Error(`Function "${name}" has been already registered in the browser context`);
|
throw new Error(`Function "${name}" has been already registered in the browser context`);
|
||||||
this._bindings.set(name, binding);
|
this._bindings.set(name, playwrightBinding);
|
||||||
await this._channel.exposeBinding({ name });
|
await this._channel.exposeBinding({ name });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,13 @@ export type BrowserContextOptions = Omit<BrowserNewContextOptions, 'viewport' |
|
||||||
type LaunchOverrides = {
|
type LaunchOverrides = {
|
||||||
ignoreDefaultArgs?: boolean | string[],
|
ignoreDefaultArgs?: boolean | string[],
|
||||||
env?: Env,
|
env?: Env,
|
||||||
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
|
||||||
logger?: LoggerSink,
|
logger?: LoggerSink,
|
||||||
};
|
};
|
||||||
export type LaunchOptions = Omit<BrowserTypeLaunchOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides;
|
type FirefoxUserPrefs = {
|
||||||
export type LaunchServerOptions = Omit<BrowserTypeLaunchServerOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides;
|
firefoxUserPrefs?: { [key: string]: string | number | boolean },
|
||||||
|
};
|
||||||
|
type LaunchOptionsBase = Omit<BrowserTypeLaunchOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides;
|
||||||
|
export type LaunchOptions = LaunchOptionsBase & FirefoxUserPrefs;
|
||||||
|
export type LaunchServerOptions = Omit<BrowserTypeLaunchServerOptions, 'ignoreAllDefaultArgs' | 'ignoreDefaultArgs' | 'env' | 'firefoxUserPrefs'> & LaunchOverrides & FirefoxUserPrefs;
|
||||||
|
export type LaunchPersistentContextOptions = LaunchOptionsBase & BrowserContextOptions;
|
||||||
export type ConnectOptions = BrowserTypeConnectParams & { logger?: LoggerSink };
|
export type ConnectOptions = BrowserTypeConnectParams & { logger?: LoggerSink };
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,6 @@ Documentation.Member = class {
|
||||||
* @param {string[]=} templates
|
* @param {string[]=} templates
|
||||||
*/
|
*/
|
||||||
constructor(kind, name, type, argsArray, comment = '', returnComment = '', required = true, templates = []) {
|
constructor(kind, name, type, argsArray, comment = '', returnComment = '', required = true, templates = []) {
|
||||||
if (name === 'code') debugger;
|
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ function checkSources(sources) {
|
||||||
parent = parent.parent;
|
parent = parent.parent;
|
||||||
className = path.basename(parent.fileName, '.js');
|
className = path.basename(parent.fileName, '.js');
|
||||||
}
|
}
|
||||||
if (className && !excludeClasses.has(className)) {
|
if (className && !excludeClasses.has(className) && !fileName.endsWith('/protocol.ts')) {
|
||||||
excludeClasses.add(className);
|
excludeClasses.add(className);
|
||||||
const renamed = expandPrefix(className);
|
const renamed = expandPrefix(className);
|
||||||
classes.push(serializeClass(renamed, symbol, node));
|
classes.push(serializeClass(renamed, symbol, node));
|
||||||
|
|
@ -194,7 +194,7 @@ function checkSources(sources) {
|
||||||
} else if (isRegularObject(type)) {
|
} else if (isRegularObject(type)) {
|
||||||
let properties = undefined;
|
let properties = undefined;
|
||||||
if (!circular.includes(typeName))
|
if (!circular.includes(typeName))
|
||||||
properties = type.getProperties().map(property => serializeSymbol(property, nextCircular));
|
properties = getTypeProperties(type).map(property => serializeSymbol(property, nextCircular));
|
||||||
return new Documentation.Type('Object', properties);
|
return new Documentation.Type('Object', properties);
|
||||||
}
|
}
|
||||||
if (type.isUnion() && (typeName.includes('|') || type.types.every(type => type.isStringLiteral() || type.intrinsicName === 'number'))) {
|
if (type.isUnion() && (typeName.includes('|') || type.types.every(type => type.isStringLiteral() || type.intrinsicName === 'number'))) {
|
||||||
|
|
@ -284,6 +284,26 @@ function checkSources(sources) {
|
||||||
function serializeProperty(name, type) {
|
function serializeProperty(name, type) {
|
||||||
return Documentation.Member.createProperty(name, serializeType(type));
|
return Documentation.Member.createProperty(name, serializeType(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!ts.Type} type
|
||||||
|
*/
|
||||||
|
function getTypeProperties(type) {
|
||||||
|
if (type.aliasSymbol && type.aliasSymbol.escapedName === 'Pick') {
|
||||||
|
const props = getTypeProperties(type.aliasTypeArguments[0]);
|
||||||
|
const pickNames = type.aliasTypeArguments[1].types.map(t => t.value);
|
||||||
|
return props.filter(p => pickNames.includes(p.getName()));
|
||||||
|
}
|
||||||
|
if (!type.isIntersection())
|
||||||
|
return type.getProperties();
|
||||||
|
let props = [];
|
||||||
|
for (const innerType of type.types) {
|
||||||
|
let innerProps = getTypeProperties(innerType);
|
||||||
|
props = props.filter(p => !innerProps.find(e => e.getName() === p.getName()));
|
||||||
|
props.push(...innerProps);
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandPrefix(name) {
|
function expandPrefix(name) {
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,9 @@ const jsBuilder = require('./JSBuilder');
|
||||||
const mdBuilder = require('./MDBuilder');
|
const mdBuilder = require('./MDBuilder');
|
||||||
const Documentation = require('./Documentation');
|
const Documentation = require('./Documentation');
|
||||||
const Message = require('../Message');
|
const Message = require('../Message');
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const EXCLUDE_PROPERTIES = new Set([
|
const EXCLUDE_PROPERTIES = new Set([
|
||||||
'Browser.create',
|
|
||||||
'Headers.fromPayload',
|
|
||||||
'Page.create',
|
|
||||||
'JSHandle.toString',
|
'JSHandle.toString',
|
||||||
'TimeoutError.name',
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ run();
|
||||||
async function run() {
|
async function run() {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const onlyBrowserVersions = process.argv.includes('--only-browser-versions');
|
const onlyBrowserVersions = process.argv.includes('--only-browser-versions');
|
||||||
|
const channel = process.argv.includes('--channel');
|
||||||
|
if (channel)
|
||||||
|
console.warn(`${YELLOW_COLOR}NOTE: checking documentation against //src/rpc/client${RESET_COLOR}`);
|
||||||
|
|
||||||
/** @type {!Array<!Message>} */
|
/** @type {!Array<!Message>} */
|
||||||
const messages = [];
|
const messages = [];
|
||||||
|
|
@ -66,8 +69,13 @@ async function run() {
|
||||||
const browser = await playwright.chromium.launch();
|
const browser = await playwright.chromium.launch();
|
||||||
const page = await browser.newPage();
|
const page = await browser.newPage();
|
||||||
const checkPublicAPI = require('./check_public_api');
|
const checkPublicAPI = require('./check_public_api');
|
||||||
const rpcDir = path.join(PROJECT_DIR, 'src', 'rpc');
|
let jsSources;
|
||||||
const jsSources = await Source.readdir(path.join(PROJECT_DIR, 'src'), '', [rpcDir]);
|
if (channel) {
|
||||||
|
jsSources = await Source.readdir(path.join(PROJECT_DIR, 'src', 'rpc', 'client'), '', []);
|
||||||
|
} else {
|
||||||
|
const rpcDir = path.join(PROJECT_DIR, 'src', 'rpc');
|
||||||
|
jsSources = await Source.readdir(path.join(PROJECT_DIR, 'src'), '', [rpcDir]);
|
||||||
|
}
|
||||||
messages.push(...await checkPublicAPI(page, [api], jsSources));
|
messages.push(...await checkPublicAPI(page, [api], jsSources));
|
||||||
await browser.close();
|
await browser.close();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue