diff --git a/index.d.ts b/index.d.ts index 79897e0a2a..183459231d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -18,3 +18,4 @@ export * from './lib/api'; export function playwright(browser: 'chromium'): import('./lib/api').ChromiumPlaywright; export function playwright(browser: 'firefox'): import('./lib/api').FirefoxPlaywright; export function playwright(browser: 'webkit'): import('./lib/api').WebKitPlaywright; +export function connect(browser: 'chromium'): import('./lib/api').ChromiumBrowser.connect; diff --git a/index.js b/index.js index df942e92aa..571c21677c 100644 --- a/index.js +++ b/index.js @@ -33,3 +33,9 @@ module.exports.playwright = browser => { return new api.WebKitPlaywright(__dirname, packageJson.playwright.webkit_revision); throw new Error(`Unsupported browser "${browser}"`); }; + +module.exports.connect = browser => { + if (browser === 'chromium') + return api.ChromiumBrowser.connect; + throw new Error(`Unsupported browser "${browser}"`); +}; diff --git a/src/api.ts b/src/api.ts index 3b8d06cba5..ff07115f4d 100644 --- a/src/api.ts +++ b/src/api.ts @@ -17,7 +17,6 @@ export { Accessibility } from './accessibility'; export { Browser, BrowserServer } from './browser'; export { BrowserContext } from './browserContext'; -export { BrowserFetcher } from './browserFetcher'; export { ConsoleMessage } from './console'; export { Dialog } from './dialog'; export { ElementHandle } from './dom'; @@ -28,6 +27,9 @@ export { JSHandle } from './javascript'; export { Request, Response } from './network'; export { Coverage, FileChooser, Page, Worker } from './page'; +export { BrowserFetcher } from './server/browserFetcher'; +export { CRPlaywright as ChromiumPlaywright, CRBrowserServer as ChromiumBrowserServer } from './server/crPlaywright'; + export * from './chromium/crApi'; export * from './firefox/ffApi'; export * from './webkit/wkApi'; diff --git a/src/chromium/crApi.ts b/src/chromium/crApi.ts index abf5110ecb..b6fbfea0c0 100644 --- a/src/chromium/crApi.ts +++ b/src/chromium/crApi.ts @@ -16,5 +16,4 @@ export { CRBrowser as ChromiumBrowser } from './crBrowser'; export { CRSession as ChromiumSession } from './crConnection'; -export { CRPlaywright as ChromiumPlaywright } from './crPlaywright'; export { CRTarget as ChromiumTarget } from './crTarget'; diff --git a/src/chromium/crBrowser.ts b/src/chromium/crBrowser.ts index ad44d2b2b4..d99cf4e090 100644 --- a/src/chromium/crBrowser.ts +++ b/src/chromium/crBrowser.ts @@ -28,9 +28,16 @@ import * as browser from '../browser'; import * as network from '../network'; import * as types from '../types'; import * as platform from '../platform'; -import { ConnectionTransport } from '../transport'; +import { ConnectionTransport, SlowMoTransport } from '../transport'; import { readProtocolStream } from './crProtocolHelper'; +export type CRConnectOptions = { + slowMo?: number, + browserWSEndpoint?: string; + browserURL?: string; + transport?: ConnectionTransport; +}; + export class CRBrowser extends browser.Browser { _connection: CRConnection; _client: CRSession; @@ -42,10 +49,9 @@ export class CRBrowser extends browser.Browser { private _tracingPath = ''; private _tracingClient: CRSession | undefined; - static async create( - transport: ConnectionTransport) { + static async connect(options: CRConnectOptions): Promise { + const transport = await createTransport(options); const connection = new CRConnection(transport); - const { browserContextIds } = await connection.rootSession.send('Target.getBrowserContexts'); const browser = new CRBrowser(connection, browserContextIds); await connection.rootSession.send('Target.setDiscoverTargets', { discover: true }); @@ -297,3 +303,25 @@ export class CRBrowser extends browser.Browser { return !this._connection._closed; } } + +export async function createTransport(options: CRConnectOptions): Promise { + assert(Number(!!options.browserWSEndpoint) + Number(!!options.browserURL) + Number(!!options.transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to playwright.connect'); + let transport: ConnectionTransport | undefined; + let connectionURL: string = ''; + if (options.transport) { + transport = options.transport; + } else if (options.browserWSEndpoint) { + connectionURL = options.browserWSEndpoint; + transport = await platform.createWebSocketTransport(options.browserWSEndpoint); + } else if (options.browserURL) { + try { + const data = await platform.fetchUrl(new URL('/json/version', options.browserURL).href); + connectionURL = JSON.parse(data).webSocketDebuggerUrl; + } catch (e) { + e.message = `Failed to fetch browser webSocket url from ${options.browserURL}: ` + e.message; + throw e; + } + transport = await platform.createWebSocketTransport(connectionURL); + } + return SlowMoTransport.wrap(transport, options.slowMo); +} diff --git a/src/firefox/ffLauncher.ts b/src/firefox/ffLauncher.ts index 3caf2d3ab6..619f7f49a4 100644 --- a/src/firefox/ffLauncher.ts +++ b/src/firefox/ffLauncher.ts @@ -18,14 +18,15 @@ import * as os from 'os'; import * as path from 'path'; import { FFBrowser } from './ffBrowser'; -import { BrowserFetcher, BrowserFetcherOptions } from '../browserFetcher'; +import { BrowserFetcher, BrowserFetcherOptions } from '../server/browserFetcher'; import * as fs from 'fs'; import * as util from 'util'; import { assert } from '../helper'; import { TimeoutError } from '../errors'; -import { WebSocketTransport, SlowMoTransport } from '../transport'; -import { launchProcess, waitForLine } from '../processLauncher'; +import { SlowMoTransport } from '../transport'; +import { launchProcess, waitForLine } from '../server/processLauncher'; import { BrowserServer } from '../browser'; +import * as platform from '../platform'; const mkdtempAsync = util.promisify(fs.mkdtemp); const writeFileAsync = util.promisify(fs.writeFile); @@ -122,7 +123,7 @@ export class FFLauncher { const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Firefox!`); const match = await waitForLine(launchedProcess, launchedProcess.stdout, /^Juggler listening on (ws:\/\/.*)$/, timeout, timeoutError); const url = match[1]; - const transport = await WebSocketTransport.create(url); + const transport = await platform.createWebSocketTransport(url); browser = await FFBrowser.create(SlowMoTransport.wrap(transport, slowMo)); await browser._waitForTarget(t => t.type() === 'page'); return new BrowserServer(browser, launchedProcess, url); diff --git a/src/firefox/ffPlaywright.ts b/src/firefox/ffPlaywright.ts index c6a5aaf988..97d5d6eabc 100644 --- a/src/firefox/ffPlaywright.ts +++ b/src/firefox/ffPlaywright.ts @@ -17,12 +17,13 @@ import * as browsers from '../browser'; import { FFBrowser } from './ffBrowser'; -import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../browserFetcher'; -import { WebSocketTransport, SlowMoTransport } from '../transport'; +import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../server/browserFetcher'; +import { SlowMoTransport } from '../transport'; import { DeviceDescriptors } from '../deviceDescriptors'; import * as Errors from '../errors'; import * as types from '../types'; import { FFLauncher, createBrowserFetcher } from './ffLauncher'; +import * as platform from '../platform'; export class FFPlaywright { private _projectRoot: string; @@ -52,7 +53,7 @@ export class FFPlaywright { } async connect(options: { slowMo?: number, browserWSEndpoint: string }): Promise { - const transport = await WebSocketTransport.create(options.browserWSEndpoint); + const transport = await platform.createWebSocketTransport(options.browserWSEndpoint); return FFBrowser.create(SlowMoTransport.wrap(transport, options.slowMo || 0)); } diff --git a/src/platform.ts b/src/platform.ts index c3f4b12614..f8f5a954a8 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -9,9 +9,13 @@ import * as nodeBuffer from 'buffer'; import * as mime from 'mime'; import * as jpeg from 'jpeg-js'; import * as png from 'pngjs'; +import * as http from 'http'; +import * as https from 'https'; +import * as NodeWebSocket from 'ws'; import { assert, helper } from './helper'; import * as types from './types'; +import { ConnectionTransport } from './transport'; export const isNode = typeof process === 'object' && !!process && typeof process.versions === 'object' && !!process.versions && !!process.versions.node; @@ -219,3 +223,79 @@ export function pngToJpeg(buffer: Buffer): Buffer { assert(isNode, 'Converting from png to jpeg is only supported in Node.js'); return jpeg.encode(png.PNG.sync.read(buffer)).data; } + +function nodeFetch(url: string): Promise { + let resolve: (url: string) => void; + let reject: (e: Error) => void; + const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); + + const endpointURL = new URL(url); + const protocol = endpointURL.protocol === 'https:' ? https : http; + const request = protocol.request(endpointURL, res => { + let data = ''; + if (res.statusCode !== 200) { + // Consume response data to free up memory. + res.resume(); + reject(new Error('HTTP ' + res.statusCode)); + return; + } + res.setEncoding('utf8'); + res.on('data', chunk => data += chunk); + res.on('end', () => resolve(data)); + }); + + request.on('error', reject); + request.end(); + + return promise; +} + +export function fetchUrl(url: string): Promise { + if (isNode) + return nodeFetch(url); + return fetch(url).then(response => { + if (!response.ok) + throw new Error('HTTP ' + response.status + ' ' + response.statusText); + return response.text(); + }); +} + +class WebSocketTransport implements ConnectionTransport { + private _ws: WebSocket; + + onmessage?: (message: string) => void; + onclose?: () => void; + + constructor(ws: WebSocket) { + this._ws = ws; + this._ws.addEventListener('message', event => { + if (this.onmessage) + this.onmessage.call(null, event.data); + }); + this._ws.addEventListener('close', event => { + if (this.onclose) + this.onclose.call(null); + }); + // Silently ignore all errors - we don't know what to do with them. + this._ws.addEventListener('error', () => {}); + } + + send(message: string) { + this._ws.send(message); + } + + close() { + this._ws.close(); + } +} + +export function createWebSocketTransport(url: string): Promise { + return new Promise((resolve, reject) => { + const ws = (isNode ? new NodeWebSocket(url, [], { + perMessageDeflate: false, + maxPayload: 256 * 1024 * 1024, // 256Mb + }) : new WebSocket(url)) as WebSocket; + ws.addEventListener('open', () => resolve(new WebSocketTransport(ws))); + ws.addEventListener('error', reject); + }); +} diff --git a/src/browserFetcher.ts b/src/server/browserFetcher.ts similarity index 96% rename from src/browserFetcher.ts rename to src/server/browserFetcher.ts index 540f550bc5..a141dc909c 100644 --- a/src/browserFetcher.ts +++ b/src/server/browserFetcher.ts @@ -19,21 +19,20 @@ import * as extract from 'extract-zip'; import * as fs from 'fs'; import * as ProxyAgent from 'https-proxy-agent'; import * as path from 'path'; -import * as platform from './platform'; -// @ts-ignore +import * as platform from '../platform'; import { getProxyForUrl } from 'proxy-from-env'; import * as removeRecursive from 'rimraf'; import * as URL from 'url'; -import { assert } from './helper'; +import { assert } from '../helper'; const readdirAsync = platform.promisify(fs.readdir.bind(fs)); const mkdirAsync = platform.promisify(fs.mkdir.bind(fs)); const unlinkAsync = platform.promisify(fs.unlink.bind(fs)); const chmodAsync = platform.promisify(fs.chmod.bind(fs)); -function existsAsync(filePath) { - let fulfill = null; - const promise = new Promise(x => fulfill = x); +function existsAsync(filePath: string): Promise { + let fulfill: (exists: boolean) => void; + const promise = new Promise(x => fulfill = x); fs.access(filePath, err => fulfill(!err)); return promise; } diff --git a/src/chromium/crPlaywright.ts b/src/server/crPlaywright.ts similarity index 77% rename from src/chromium/crPlaywright.ts rename to src/server/crPlaywright.ts index 9329d53cc9..c95f4df37d 100644 --- a/src/chromium/crPlaywright.ts +++ b/src/server/crPlaywright.ts @@ -15,25 +15,22 @@ * limitations under the License. */ -import * as http from 'http'; -import * as https from 'https'; -import * as URL from 'url'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import * as util from 'util'; -import { BrowserFetcher, BrowserFetcherOptions, BrowserFetcherRevisionInfo, OnProgressCallback } from '../browserFetcher'; +import { BrowserFetcher, BrowserFetcherOptions, BrowserFetcherRevisionInfo, OnProgressCallback } from '../server/browserFetcher'; import { DeviceDescriptors } from '../deviceDescriptors'; import * as Errors from '../errors'; import * as types from '../types'; import { assert } from '../helper'; -import { ConnectionTransport, WebSocketTransport, SlowMoTransport, PipeTransport } from '../transport'; -import { CRBrowser } from './crBrowser'; +import { CRBrowser, CRConnectOptions, createTransport } from '../chromium/crBrowser'; import * as platform from '../platform'; import { TimeoutError } from '../errors'; -import { launchProcess, waitForLine } from '../processLauncher'; +import { launchProcess, waitForLine } from '../server/processLauncher'; import { ChildProcess } from 'child_process'; -import { CRConnection } from './crConnection'; +import { CRConnection } from '../chromium/crConnection'; +import { PipeTransport } from './pipeTransport'; export type SlowMoOptions = { slowMo?: number, @@ -58,24 +55,17 @@ export type LaunchOptions = ChromeArgOptions & SlowMoOptions & { pipe?: boolean, }; -export type ConnectOptions = SlowMoOptions & { - browserWSEndpoint?: string; - browserURL?: string; - transport?: ConnectionTransport; -}; - export class CRBrowserServer { private _process: ChildProcess; - private _connectOptions: ConnectOptions; + private _connectOptions: CRConnectOptions; - constructor(process: ChildProcess, connectOptions: ConnectOptions) { + constructor(process: ChildProcess, connectOptions: CRConnectOptions) { this._process = process; this._connectOptions = connectOptions; } async connect(): Promise { - const transport = await createTransport(this._connectOptions); - return CRBrowser.create(transport); + return CRBrowser.connect(this._connectOptions); } process(): ChildProcess { @@ -86,7 +76,7 @@ export class CRBrowserServer { return this._connectOptions.browserWSEndpoint || null; } - connectOptions(): ConnectOptions { + connectOptions(): CRConnectOptions { return this._connectOptions; } @@ -179,7 +169,7 @@ export class CRPlaywright { let server: CRBrowserServer | undefined; try { - let connectOptions: ConnectOptions | undefined; + let connectOptions: CRConnectOptions | undefined; let browserWSEndpoint: string = ''; if (!usePipe) { const timeoutError = new TimeoutError(`Timed out after ${timeout} ms while trying to connect to Chrome! The only Chrome revision guaranteed to work is r${this._revision}`); @@ -199,9 +189,8 @@ export class CRPlaywright { } } - async connect(options: ConnectOptions): Promise { - const transport = await createTransport(options); - return CRBrowser.create(transport); + async connect(options: CRConnectOptions): Promise { + return CRBrowser.connect(options); } executablePath(): string { @@ -328,49 +317,3 @@ const DEFAULT_ARGS = [ '--password-store=basic', '--use-mock-keychain', ]; - -function getWSEndpoint(browserURL: string): Promise { - let resolve: (url: string) => void; - let reject: (e: Error) => void; - const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); - - const endpointURL = URL.resolve(browserURL, '/json/version'); - const protocol = endpointURL.startsWith('https') ? https : http; - const requestOptions = Object.assign(URL.parse(endpointURL), { method: 'GET' }); - const request = protocol.request(requestOptions, res => { - let data = ''; - if (res.statusCode !== 200) { - // Consume response data to free up memory. - res.resume(); - reject(new Error('HTTP ' + res.statusCode)); - return; - } - res.setEncoding('utf8'); - res.on('data', chunk => data += chunk); - res.on('end', () => resolve(JSON.parse(data).webSocketDebuggerUrl)); - }); - - request.on('error', reject); - request.end(); - - return promise.catch(e => { - e.message = `Failed to fetch browser webSocket url from ${endpointURL}: ` + e.message; - throw e; - }); -} - -async function createTransport(options: ConnectOptions): Promise { - assert(Number(!!options.browserWSEndpoint) + Number(!!options.browserURL) + Number(!!options.transport) === 1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to playwright.connect'); - let transport: ConnectionTransport | undefined; - let connectionURL: string = ''; - if (options.transport) { - transport = options.transport; - } else if (options.browserWSEndpoint) { - connectionURL = options.browserWSEndpoint; - transport = await WebSocketTransport.create(options.browserWSEndpoint); - } else if (options.browserURL) { - connectionURL = await getWSEndpoint(options.browserURL); - transport = await WebSocketTransport.create(connectionURL); - } - return SlowMoTransport.wrap(transport, options.slowMo); -} diff --git a/src/server/pipeTransport.ts b/src/server/pipeTransport.ts new file mode 100644 index 0000000000..55919243e3 --- /dev/null +++ b/src/server/pipeTransport.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * Modifications 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 { debugError, helper, RegisteredListener } from '../helper'; +import { ConnectionTransport } from '../transport'; + +export class PipeTransport implements ConnectionTransport { + private _pipeWrite: NodeJS.WritableStream; + private _pendingMessage = ''; + private _eventListeners: RegisteredListener[]; + onmessage?: (message: string) => void; + onclose?: () => void; + + constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) { + this._pipeWrite = pipeWrite; + this._eventListeners = [ + helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)), + helper.addEventListener(pipeRead, 'close', () => { + if (this.onclose) + this.onclose.call(null); + }), + helper.addEventListener(pipeRead, 'error', debugError), + helper.addEventListener(pipeWrite, 'error', debugError), + ]; + this.onmessage = null; + this.onclose = null; + } + + send(message: string) { + this._pipeWrite.write(message); + this._pipeWrite.write('\0'); + } + + _dispatch(buffer: Buffer) { + let end = buffer.indexOf('\0'); + if (end === -1) { + this._pendingMessage += buffer.toString(); + return; + } + const message = this._pendingMessage + buffer.toString(undefined, 0, end); + if (this.onmessage) + this.onmessage.call(null, message); + + let start = end + 1; + end = buffer.indexOf('\0', start); + while (end !== -1) { + if (this.onmessage) + this.onmessage.call(null, buffer.toString(undefined, start, end)); + start = end + 1; + end = buffer.indexOf('\0', start); + } + this._pendingMessage = buffer.toString(undefined, start); + } + + close() { + this._pipeWrite = null; + helper.removeEventListeners(this._eventListeners); + } +} diff --git a/src/processLauncher.ts b/src/server/processLauncher.ts similarity index 97% rename from src/processLauncher.ts rename to src/server/processLauncher.ts index 073a72c4f3..f4d6c68200 100644 --- a/src/processLauncher.ts +++ b/src/server/processLauncher.ts @@ -18,10 +18,10 @@ import * as childProcess from 'child_process'; import * as stream from 'stream'; import * as removeFolder from 'rimraf'; -import { helper } from './helper'; +import { helper } from '../helper'; import * as readline from 'readline'; -import { TimeoutError } from './errors'; -import * as platform from './platform'; +import { TimeoutError } from '../errors'; +import * as platform from '../platform'; const removeFolderAsync = platform.promisify(removeFolder); diff --git a/src/transport.ts b/src/transport.ts index 7ab2cb83e1..feec07e495 100644 --- a/src/transport.ts +++ b/src/transport.ts @@ -15,9 +15,6 @@ * limitations under the License. */ -import * as WebSocket from 'ws'; -import { debugError, helper, RegisteredListener } from './helper'; - export interface ConnectionTransport { send(s: string): void; close(): void; @@ -25,100 +22,6 @@ export interface ConnectionTransport { onclose?: () => void, } -export class WebSocketTransport implements ConnectionTransport { - private _ws: WebSocket; - - onmessage?: (message: string) => void; - onclose?: () => void; - - static create(url: string): Promise { - return new Promise((resolve, reject) => { - const ws = new WebSocket(url, [], { - perMessageDeflate: false, - maxPayload: 256 * 1024 * 1024, // 256Mb - }); - ws.addEventListener('open', () => resolve(new WebSocketTransport(ws, url))); - ws.addEventListener('error', reject); - }); - } - - constructor(ws: WebSocket, url: string) { - this._ws = ws; - this._ws.addEventListener('message', event => { - if (this.onmessage) - this.onmessage.call(null, event.data); - }); - this._ws.addEventListener('close', event => { - if (this.onclose) - this.onclose.call(null); - }); - // Silently ignore all errors - we don't know what to do with them. - this._ws.addEventListener('error', () => {}); - } - - send(message: string) { - this._ws.send(message); - } - - close() { - this._ws.close(); - } -} - -export class PipeTransport implements ConnectionTransport { - private _pipeWrite: NodeJS.WritableStream; - private _pendingMessage = ''; - private _eventListeners: RegisteredListener[]; - onmessage?: (message: string) => void; - onclose?: () => void; - - constructor(pipeWrite: NodeJS.WritableStream, pipeRead: NodeJS.ReadableStream) { - this._pipeWrite = pipeWrite; - this._eventListeners = [ - helper.addEventListener(pipeRead, 'data', buffer => this._dispatch(buffer)), - helper.addEventListener(pipeRead, 'close', () => { - if (this.onclose) - this.onclose.call(null); - }), - helper.addEventListener(pipeRead, 'error', debugError), - helper.addEventListener(pipeWrite, 'error', debugError), - ]; - this.onmessage = null; - this.onclose = null; - } - - send(message: string) { - this._pipeWrite.write(message); - this._pipeWrite.write('\0'); - } - - _dispatch(buffer: Buffer) { - let end = buffer.indexOf('\0'); - if (end === -1) { - this._pendingMessage += buffer.toString(); - return; - } - const message = this._pendingMessage + buffer.toString(undefined, 0, end); - if (this.onmessage) - this.onmessage.call(null, message); - - let start = end + 1; - end = buffer.indexOf('\0', start); - while (end !== -1) { - if (this.onmessage) - this.onmessage.call(null, buffer.toString(undefined, start, end)); - start = end + 1; - end = buffer.indexOf('\0', start); - } - this._pendingMessage = buffer.toString(undefined, start); - } - - close() { - this._pipeWrite = null; - helper.removeEventListeners(this._eventListeners); - } -} - export class SlowMoTransport { private readonly _delay: number; private readonly _delegate: ConnectionTransport; diff --git a/src/webkit/wkLauncher.ts b/src/webkit/wkLauncher.ts index c4050b124c..e3acb7c0fa 100644 --- a/src/webkit/wkLauncher.ts +++ b/src/webkit/wkLauncher.ts @@ -17,14 +17,15 @@ import { assert } from '../helper'; import { WKBrowser } from './wkBrowser'; -import { BrowserFetcher, BrowserFetcherOptions } from '../browserFetcher'; -import { PipeTransport, SlowMoTransport } from '../transport'; +import { BrowserFetcher, BrowserFetcherOptions } from '../server/browserFetcher'; +import { SlowMoTransport } from '../transport'; import { execSync } from 'child_process'; import * as path from 'path'; import * as util from 'util'; import * as os from 'os'; -import { launchProcess } from '../processLauncher'; +import { launchProcess } from '../server/processLauncher'; import { BrowserServer } from '../browser'; +import { PipeTransport } from '../server/pipeTransport'; const DEFAULT_ARGS = [ ]; diff --git a/src/webkit/wkPlaywright.ts b/src/webkit/wkPlaywright.ts index d7422133ba..0f673ed557 100644 --- a/src/webkit/wkPlaywright.ts +++ b/src/webkit/wkPlaywright.ts @@ -15,7 +15,7 @@ * limitations under the License. */ import * as browsers from '../browser'; -import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../browserFetcher'; +import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../server/browserFetcher'; import { DeviceDescriptors } from '../deviceDescriptors'; import * as Errors from '../errors'; import * as types from '../types'; diff --git a/utils/doclint/check_public_api/JSBuilder.js b/utils/doclint/check_public_api/JSBuilder.js index 86e652f06b..95c8fd6753 100644 --- a/utils/doclint/check_public_api/JSBuilder.js +++ b/utils/doclint/check_public_api/JSBuilder.js @@ -98,11 +98,12 @@ function checkSources(sources) { excludeClasses.add(className); } } - if (!node.getSourceFile().fileName.endsWith('platform.ts')) { + const fileName = node.getSourceFile().fileName; + if (!fileName.endsWith('platform.ts') && !fileName.includes('src/server/')) { // Only relative imports. if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) { const module = node.moduleSpecifier.text; - if (!module.startsWith('.')) { + if (!module.startsWith('.') || path.resolve(path.dirname(fileName), module).includes('src/server')) { const lac = ts.getLineAndCharacterOfPosition(node.getSourceFile(), node.moduleSpecifier.pos); errors.push(`Disallowed import "${module}" at ${node.getSourceFile().fileName}:${lac.line + 1}`); }