未验证 提交 88da4110 编写于 作者: M Miguel Solorio 提交者: GitHub

Merge branch 'master' into misolori/octicon-update

......@@ -107,6 +107,16 @@ steps:
displayName: Run integration tests
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
# - script: |
# set -e
# cd test/smoke
# yarn compile
# cd -
# yarn smoketest --web --headless
# continueOnError: true
# displayName: Run smoke tests
# condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
- script: |
set -e
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd
......
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.32315L5.96154 13.3232L5.17083 13.2874L1.82083 8.51736L2.63918 7.94263L5.617 12.1827L13.6685 2.67683L14.4315 3.32315Z" fill="#C5C5C5"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.32317L5.96154 13.3232L5.17083 13.2874L1.82083 8.51737L2.63918 7.94264L5.617 12.1827L13.6685 2.67685L14.4315 3.32317Z" fill="#424242"/>
</svg>
......@@ -209,7 +209,7 @@ export class MarkdownContentProvider {
return `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; media-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*; script-src 'nonce-${nonce}'; style-src 'self' ${rule} 'unsafe-inline' https: data: http://localhost:* http://127.0.0.1:*; font-src 'self' ${rule} https: data: http://localhost:* http://127.0.0.1:*;">`;
case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent:
return '';
return '<meta http-equiv="Content-Security-Policy" content="">';
case MarkdownPreviewSecurityLevel.Strict:
default:
......
......@@ -33,14 +33,14 @@ function isDirectory(path: string): Promise<boolean> {
});
}
enum UpdateImportsOnFileMoveSetting {
const enum UpdateImportsOnFileMoveSetting {
Prompt = 'prompt',
Always = 'always',
Never = 'never',
}
class UpdateImportsOnFileRenameHandler extends Disposable {
public static minVersion = API.v300;
public static readonly minVersion = API.v300;
public constructor(
private readonly client: ITypeScriptServiceClient,
......@@ -127,7 +127,7 @@ class UpdateImportsOnFileRenameHandler extends Disposable {
newResource: vscode.Uri,
newDocument: vscode.TextDocument
): Promise<boolean> {
enum Choice {
const enum Choice {
None = 0,
Accept = 1,
Reject = 2,
......@@ -237,4 +237,4 @@ export function register(
) {
return new VersionDependentRegistration(client, UpdateImportsOnFileRenameHandler.minVersion, () =>
new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles));
}
\ No newline at end of file
}
{
"name": "code-oss-dev",
"version": "1.38.0",
"distro": "a8a3be6f7445a6f3ce736a0ba3cbca717a2372cb",
"distro": "13f407368a517ace39c2721a66a951ba4eebce20",
"author": {
"name": "Microsoft Corporation"
},
......@@ -124,6 +124,7 @@
"optimist": "0.3.5",
"p-all": "^1.0.0",
"pump": "^1.0.1",
"puppeteer": "^1.19.0",
"queue": "3.0.6",
"rcedit": "^1.1.0",
"rimraf": "^2.2.8",
......@@ -158,4 +159,4 @@
"windows-mutex": "0.3.0",
"windows-process-tree": "0.2.4"
}
}
\ No newline at end of file
}
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.3232L5.96151 13.3232L5.1708 13.2874L1.8208 8.5174L2.63915 7.94268L5.61697 12.1827L13.6684 2.67688L14.4315 3.3232Z" fill="#C5C5C5"/>
</svg>
......@@ -293,12 +293,9 @@ function topStep<T>(array: ReadonlyArray<T>, compare: (a: T, b: T) => number, re
}
/**
* @returns a new array with all falsy values removed. The original array IS NOT modified.
* @returns New array with all falsy values removed. The original array IS NOT modified.
*/
export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
if (!array) {
return array;
}
return <T[]>array.filter(e => !!e);
}
......@@ -306,9 +303,6 @@ export function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
* Remove all falsey values from `array`. The original array IS modified.
*/
export function coalesceInPlace<T>(array: Array<T | undefined | null>): void {
if (!array) {
return;
}
let to = 0;
for (let i = 0; i < array.length; i++) {
if (!!array[i]) {
......
......@@ -127,8 +127,7 @@ export class DisposableStore implements IDisposable {
markTracked(t);
if (this._isDisposed) {
console.warn(new Error('Registering disposable on object that has already been disposed of').stack);
t.dispose();
console.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack);
} else {
this._toDispose.add(t);
}
......
......@@ -49,3 +49,26 @@ export namespace Schemas {
export const userData: string = 'vscode-userdata';
}
class RemoteAuthoritiesImpl {
private readonly _hosts: { [authority: string]: string; };
private readonly _ports: { [authority: string]: number; };
private readonly _connectionTokens: { [authority: string]: string; };
constructor() {
this._hosts = Object.create(null);
this._ports = Object.create(null);
this._connectionTokens = Object.create(null);
}
public set(authority: string, host: string, port: number): void {
this._hosts[authority] = host;
this._ports[authority] = port;
}
public setConnectionToken(authority: string, connectionToken: string): void {
this._connectionTokens[authority] = connectionToken;
}
}
export const RemoteAuthorities = new RemoteAuthoritiesImpl();
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { IDisposable, dispose, ReferenceCollection, Disposable as DisposableBase, toDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, ReferenceCollection } from 'vs/base/common/lifecycle';
class Disposable implements IDisposable {
isDisposed = false;
......@@ -50,38 +50,6 @@ suite('Lifecycle', () => {
});
});
suite('DisposableBase', () => {
test('register should not leak if object has already been disposed', () => {
let aCount = 0;
let bCount = 0;
const disposable = new class extends DisposableBase {
register(other: IDisposable) {
this._register(other);
}
};
disposable.register(toDisposable(() => ++aCount));
assert.strictEqual(aCount, 0);
assert.strictEqual(bCount, 0);
disposable.dispose();
assert.strictEqual(aCount, 1);
assert.strictEqual(bCount, 0);
// Any newly added disposables should be disposed of immediately
disposable.register(toDisposable(() => ++bCount));
assert.strictEqual(aCount, 1);
assert.strictEqual(bCount, 1);
// Further dispose calls should have no effect
disposable.dispose();
assert.strictEqual(aCount, 1);
assert.strictEqual(bCount, 1);
});
});
suite('Reference Collection', () => {
class Collection extends ReferenceCollection<number> {
private _count = 0;
......@@ -118,4 +86,4 @@ suite('Reference Collection', () => {
ref4.dispose();
assert.equal(collection.count, 0);
});
});
\ No newline at end of file
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom';
import { coalesce } from 'vs/base/common/arrays';
import { IElement, IWindowDriver } from 'vs/platform/driver/common/driver';
function serializeElement(element: Element, recursive: boolean): IElement {
const attributes = Object.create(null);
for (let j = 0; j < element.attributes.length; j++) {
const attr = element.attributes.item(j);
if (attr) {
attributes[attr.name] = attr.value;
}
}
const children: IElement[] = [];
if (recursive) {
for (let i = 0; i < element.children.length; i++) {
const child = element.children.item(i);
if (child) {
children.push(serializeElement(child, true));
}
}
}
const { left, top } = getTopLeftOffset(element as HTMLElement);
return {
tagName: element.tagName,
className: element.className,
textContent: element.textContent || '',
attributes,
children,
left,
top
};
}
export abstract class BaseWindowDriver implements IWindowDriver {
constructor() { }
abstract click(selector: string, xoffset?: number, yoffset?: number): Promise<void>;
abstract doubleClick(selector: string): Promise<void>;
async setValue(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
return Promise.reject(new Error(`Element not found: ${selector}`));
}
const inputElement = element as HTMLInputElement;
inputElement.value = text;
const event = new Event('input', { bubbles: true, cancelable: true });
inputElement.dispatchEvent(event);
}
async getTitle(): Promise<string> {
return document.title;
}
async isActiveElement(selector: string): Promise<boolean> {
const element = document.querySelector(selector);
if (element !== document.activeElement) {
const chain: string[] = [];
let el = document.activeElement;
while (el) {
const tagName = el.tagName;
const id = el.id ? `#${el.id}` : '';
const classes = coalesce(el.className.split(/\s+/g).map(c => c.trim())).map(c => `.${c}`).join('');
chain.unshift(`${tagName}${id}${classes}`);
el = el.parentElement;
}
throw new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`);
}
return true;
}
async getElements(selector: string, recursive: boolean): Promise<IElement[]> {
const query = document.querySelectorAll(selector);
const result: IElement[] = [];
for (let i = 0; i < query.length; i++) {
const element = query.item(i);
result.push(serializeElement(element, recursive));
}
return result;
}
async getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }> {
const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined;
return this._getElementXY(selector, offset);
}
async typeInEditor(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Editor not found: ${selector}`);
}
const textarea = element as HTMLTextAreaElement;
const start = textarea.selectionStart;
const newStart = start + text.length;
const value = textarea.value;
const newValue = value.substr(0, start) + text + value.substr(start);
textarea.value = newValue;
textarea.setSelectionRange(newStart, newStart);
const event = new Event('input', { 'bubbles': true, 'cancelable': true });
textarea.dispatchEvent(event);
}
async getTerminalBuffer(selector: string): Promise<string[]> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Terminal not found: ${selector}`);
}
const xterm = (element as any).xterm;
if (!xterm) {
throw new Error(`Xterm not found: ${selector}`);
}
const lines: string[] = [];
for (let i = 0; i < xterm.buffer.length; i++) {
lines.push(xterm.buffer.getLine(i)!.translateToString(true));
}
return lines;
}
async writeInTerminal(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Element not found: ${selector}`);
}
const xterm = (element as any).xterm;
if (!xterm) {
throw new Error(`Xterm not found: ${selector}`);
}
xterm._core._coreService.triggerDataEvent(text);
}
protected async _getElementXY(selector: string, offset?: { x: number, y: number }): Promise<{ x: number; y: number; }> {
const element = document.querySelector(selector);
if (!element) {
return Promise.reject(new Error(`Element not found: ${selector}`));
}
const { left, top } = getTopLeftOffset(element as HTMLElement);
const { width, height } = getClientArea(element as HTMLElement);
let x: number, y: number;
if (offset) {
x = left + offset.x;
y = top + offset.y;
} else {
x = left + (width / 2);
y = top + (height / 2);
}
x = Math.round(x);
y = Math.round(y);
return { x, y };
}
abstract async openDevTools(): Promise<void>;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver';
class BrowserWindowDriver extends BaseWindowDriver {
click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void> {
throw new Error('Method not implemented.');
}
doubleClick(selector: string): Promise<void> {
throw new Error('Method not implemented.');
}
openDevTools(): Promise<void> {
throw new Error('Method not implemented.');
}
}
export async function registerWindowDriver(): Promise<IDisposable> {
(<any>window).driver = new BrowserWindowDriver();
return toDisposable(() => {
return { dispose: () => { } };
});
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
// !! Do not remove the following START and END markers, they are parsed by the smoketest build
//*START
export interface IElement {
tagName: string;
className: string;
textContent: string;
attributes: { [name: string]: string; };
children: IElement[];
top: number;
left: number;
}
export interface IDriver {
_serviceBrand: any;
getWindowIds(): Promise<number[]>;
capturePage(windowId: number): Promise<string>;
reloadWindow(windowId: number): Promise<void>;
exitApplication(): Promise<void>;
dispatchKeybinding(windowId: number, keybinding: string): Promise<void>;
click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void>;
doubleClick(windowId: number, selector: string): Promise<void>;
setValue(windowId: number, selector: string, text: string): Promise<void>;
getTitle(windowId: number): Promise<string>;
isActiveElement(windowId: number, selector: string): Promise<boolean>;
getElements(windowId: number, selector: string, recursive?: boolean): Promise<IElement[]>;
getElementXY(windowId: number, selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }>;
typeInEditor(windowId: number, selector: string, text: string): Promise<void>;
getTerminalBuffer(windowId: number, selector: string): Promise<string[]>;
writeInTerminal(windowId: number, selector: string, text: string): Promise<void>;
}
//*END
export const ID = 'driverService';
export const IDriver = createDecorator<IDriver>(ID);
export interface IWindowDriver {
click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void>;
doubleClick(selector: string): Promise<void>;
setValue(selector: string, text: string): Promise<void>;
getTitle(): Promise<string>;
isActiveElement(selector: string): Promise<boolean>;
getElements(selector: string, recursive: boolean): Promise<IElement[]>;
getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }>;
typeInEditor(selector: string, text: string): Promise<void>;
getTerminalBuffer(selector: string): Promise<string[]>;
writeInTerminal(selector: string, text: string): Promise<void>;
}
......@@ -4,55 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IWindowDriver, IElement, WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver';
import { WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom';
import * as electron from 'electron';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { Terminal } from 'xterm';
import { timeout } from 'vs/base/common/async';
import { coalesce } from 'vs/base/common/arrays';
import { BaseWindowDriver } from 'vs/platform/driver/browser/baseDriver';
function serializeElement(element: Element, recursive: boolean): IElement {
const attributes = Object.create(null);
for (let j = 0; j < element.attributes.length; j++) {
const attr = element.attributes.item(j);
if (attr) {
attributes[attr.name] = attr.value;
}
}
const children: IElement[] = [];
if (recursive) {
for (let i = 0; i < element.children.length; i++) {
const child = element.children.item(i);
if (child) {
children.push(serializeElement(child, true));
}
}
}
const { left, top } = getTopLeftOffset(element as HTMLElement);
return {
tagName: element.tagName,
className: element.className,
textContent: element.textContent || '',
attributes,
children,
left,
top
};
}
class WindowDriver implements IWindowDriver {
class WindowDriver extends BaseWindowDriver {
constructor(
@IWindowService private readonly windowService: IWindowService
) { }
) {
super();
}
click(selector: string, xoffset?: number, yoffset?: number): Promise<void> {
const offset = typeof xoffset === 'number' && typeof yoffset === 'number' ? { x: xoffset, y: yoffset } : undefined;
......@@ -63,31 +29,6 @@ class WindowDriver implements IWindowDriver {
return this._click(selector, 2);
}
private async _getElementXY(selector: string, offset?: { x: number, y: number }): Promise<{ x: number; y: number; }> {
const element = document.querySelector(selector);
if (!element) {
return Promise.reject(new Error(`Element not found: ${selector}`));
}
const { left, top } = getTopLeftOffset(element as HTMLElement);
const { width, height } = getClientArea(element as HTMLElement);
let x: number, y: number;
if (offset) {
x = left + offset.x;
y = top + offset.y;
} else {
x = left + (width / 2);
y = top + (height / 2);
}
x = Math.round(x);
y = Math.round(y);
return { x, y };
}
private async _click(selector: string, clickCount: number, offset?: { x: number, y: number }): Promise<void> {
const { x, y } = await this._getElementXY(selector, offset);
......@@ -99,116 +40,6 @@ class WindowDriver implements IWindowDriver {
await timeout(100);
}
async setValue(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
return Promise.reject(new Error(`Element not found: ${selector}`));
}
const inputElement = element as HTMLInputElement;
inputElement.value = text;
const event = new Event('input', { bubbles: true, cancelable: true });
inputElement.dispatchEvent(event);
}
async getTitle(): Promise<string> {
return document.title;
}
async isActiveElement(selector: string): Promise<boolean> {
const element = document.querySelector(selector);
if (element !== document.activeElement) {
const chain: string[] = [];
let el = document.activeElement;
while (el) {
const tagName = el.tagName;
const id = el.id ? `#${el.id}` : '';
const classes = coalesce(el.className.split(/\s+/g).map(c => c.trim())).map(c => `.${c}`).join('');
chain.unshift(`${tagName}${id}${classes}`);
el = el.parentElement;
}
throw new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`);
}
return true;
}
async getElements(selector: string, recursive: boolean): Promise<IElement[]> {
const query = document.querySelectorAll(selector);
const result: IElement[] = [];
for (let i = 0; i < query.length; i++) {
const element = query.item(i);
result.push(serializeElement(element, recursive));
}
return result;
}
async typeInEditor(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Editor not found: ${selector}`);
}
const textarea = element as HTMLTextAreaElement;
const start = textarea.selectionStart;
const newStart = start + text.length;
const value = textarea.value;
const newValue = value.substr(0, start) + text + value.substr(start);
textarea.value = newValue;
textarea.setSelectionRange(newStart, newStart);
const event = new Event('input', { 'bubbles': true, 'cancelable': true });
textarea.dispatchEvent(event);
}
async getTerminalBuffer(selector: string): Promise<string[]> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Terminal not found: ${selector}`);
}
const xterm: Terminal = (element as any).xterm;
if (!xterm) {
throw new Error(`Xterm not found: ${selector}`);
}
const lines: string[] = [];
for (let i = 0; i < xterm.buffer.length; i++) {
lines.push(xterm.buffer.getLine(i)!.translateToString(true));
}
return lines;
}
async writeInTerminal(selector: string, text: string): Promise<void> {
const element = document.querySelector(selector);
if (!element) {
throw new Error(`Element not found: ${selector}`);
}
const xterm: Terminal = (element as any).xterm;
if (!xterm) {
throw new Error(`Xterm not found: ${selector}`);
}
xterm._core._coreService.triggerDataEvent(text);
}
async openDevTools(): Promise<void> {
await this.windowService.openDevTools({ mode: 'detach' });
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDriver, DriverChannel, IElement, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel, IWindowDriver, IDriverOptions } from 'vs/platform/driver/node/driver';
import { DriverChannel, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel, IDriverOptions } from 'vs/platform/driver/node/driver';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { serve as serveNet } from 'vs/base/parts/ipc/node/ipc.net';
import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle';
......@@ -17,6 +17,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { ScanCodeBinding } from 'vs/base/common/scanCode';
import { KeybindingParser } from 'vs/base/common/keybindingParser';
import { timeout } from 'vs/base/common/async';
import { IDriver, IElement, IWindowDriver } from 'vs/platform/driver/common/driver';
function isSilentKeyCode(keyCode: KeyCode) {
return keyCode < KeyCode.KEY_0;
......@@ -163,6 +164,11 @@ export class Driver implements IDriver, IWindowDriverRegistry {
return await windowDriver.getElements(selector, recursive);
}
async getElementXY(windowId: number, selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }> {
const windowDriver = await this.getWindowDriver(windowId);
return await windowDriver.getElementXY(selector, xoffset, yoffset);
}
async typeInEditor(windowId: number, selector: string, text: string): Promise<void> {
const windowDriver = await this.getWindowDriver(windowId);
await windowDriver.typeInEditor(selector, text);
......
......@@ -5,45 +5,9 @@
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
export const ID = 'driverService';
export const IDriver = createDecorator<IDriver>(ID);
// !! Do not remove the following START and END markers, they are parsed by the smoketest build
//*START
export interface IElement {
tagName: string;
className: string;
textContent: string;
attributes: { [name: string]: string; };
children: IElement[];
top: number;
left: number;
}
export interface IDriver {
_serviceBrand: any;
getWindowIds(): Promise<number[]>;
capturePage(windowId: number): Promise<string>;
reloadWindow(windowId: number): Promise<void>;
exitApplication(): Promise<void>;
dispatchKeybinding(windowId: number, keybinding: string): Promise<void>;
click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void>;
doubleClick(windowId: number, selector: string): Promise<void>;
setValue(windowId: number, selector: string, text: string): Promise<void>;
getTitle(windowId: number): Promise<string>;
isActiveElement(windowId: number, selector: string): Promise<boolean>;
getElements(windowId: number, selector: string, recursive?: boolean): Promise<IElement[]>;
typeInEditor(windowId: number, selector: string, text: string): Promise<void>;
getTerminalBuffer(windowId: number, selector: string): Promise<string[]>;
writeInTerminal(windowId: number, selector: string, text: string): Promise<void>;
}
//*END
import { IDriver, IElement, IWindowDriver } from 'vs/platform/driver/common/driver';
export class DriverChannel implements IServerChannel {
......@@ -66,6 +30,7 @@ export class DriverChannel implements IServerChannel {
case 'getTitle': return this.driver.getTitle(arg[0]);
case 'isActiveElement': return this.driver.isActiveElement(arg[0], arg[1]);
case 'getElements': return this.driver.getElements(arg[0], arg[1], arg[2]);
case 'getElementXY': return this.driver.getElementXY(arg[0], arg[1], arg[2]);
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1], arg[2]);
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg[0], arg[1]);
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1], arg[2]);
......@@ -125,6 +90,10 @@ export class DriverChannelClient implements IDriver {
return this.channel.call('getElements', [windowId, selector, recursive]);
}
getElementXY(windowId: number, selector: string, xoffset: number | undefined, yoffset: number | undefined): Promise<{ x: number, y: number }> {
return this.channel.call('getElementXY', [windowId, selector, xoffset, yoffset]);
}
typeInEditor(windowId: number, selector: string, text: string): Promise<void> {
return this.channel.call('typeInEditor', [windowId, selector, text]);
}
......@@ -180,18 +149,6 @@ export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry
}
}
export interface IWindowDriver {
click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void>;
doubleClick(selector: string): Promise<void>;
setValue(selector: string, text: string): Promise<void>;
getTitle(): Promise<string>;
isActiveElement(selector: string): Promise<boolean>;
getElements(selector: string, recursive: boolean): Promise<IElement[]>;
typeInEditor(selector: string, text: string): Promise<void>;
getTerminalBuffer(selector: string): Promise<string[]>;
writeInTerminal(selector: string, text: string): Promise<void>;
}
export class WindowDriverChannel implements IServerChannel {
constructor(private driver: IWindowDriver) { }
......@@ -208,6 +165,7 @@ export class WindowDriverChannel implements IServerChannel {
case 'getTitle': return this.driver.getTitle();
case 'isActiveElement': return this.driver.isActiveElement(arg);
case 'getElements': return this.driver.getElements(arg[0], arg[1]);
case 'getElementXY': return this.driver.getElementXY(arg[0], arg[1], arg[2]);
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1]);
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg);
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1]);
......@@ -247,6 +205,10 @@ export class WindowDriverChannelClient implements IWindowDriver {
return this.channel.call('getElements', [selector, recursive]);
}
getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number, y: number }> {
return this.channel.call('getElementXY', [selector, xoffset, yoffset]);
}
typeInEditor(selector: string, text: string): Promise<void> {
return this.channel.call('typeInEditor', [selector, text]);
}
......
......@@ -620,26 +620,26 @@ export interface IReadFileOptions {
* that have been read already with the same etag.
* It is the task of the caller to makes sure to handle this error case from the promise.
*/
etag?: string;
readonly etag?: string;
/**
* Is an integer specifying where to begin reading from in the file. If position is null,
* data will be read from the current file position.
*/
position?: number;
readonly position?: number;
/**
* Is an integer specifying how many bytes to read from the file. By default, all bytes
* will be read.
*/
length?: number;
readonly length?: number;
/**
* If provided, the size of the file will be checked against the limits.
*/
limits?: {
size?: number;
memory?: number;
readonly size?: number;
readonly memory?: number;
};
}
......@@ -648,12 +648,12 @@ export interface IWriteFileOptions {
/**
* The last known modification time of the file. This can be used to prevent dirty writes.
*/
mtime?: number;
readonly mtime?: number;
/**
* The etag of the file. This can be used to prevent dirty writes.
*/
etag?: string;
readonly etag?: string;
}
export interface IResolveFileOptions {
......@@ -662,22 +662,22 @@ export interface IResolveFileOptions {
* Automatically continue resolving children of a directory until the provided resources
* are found.
*/
resolveTo?: URI[];
readonly resolveTo?: readonly URI[];
/**
* Automatically continue resolving children of a directory if the number of children is 1.
*/
resolveSingleChildDescendants?: boolean;
readonly resolveSingleChildDescendants?: boolean;
/**
* Will resolve mtime, size and etag of files if enabled. This can have a negative impact
* on performance and thus should only be used when these values are required.
*/
resolveMetadata?: boolean;
readonly resolveMetadata?: boolean;
}
export interface IResolveMetadataFileOptions extends IResolveFileOptions {
resolveMetadata: true;
readonly resolveMetadata: true;
}
export interface ICreateFileOptions {
......@@ -686,7 +686,7 @@ export interface ICreateFileOptions {
* Overwrite the file to create if it already exists on disk. Otherwise
* an error will be thrown (FILE_MODIFIED_SINCE).
*/
overwrite?: boolean;
readonly overwrite?: boolean;
}
export class FileOperationError extends Error {
......
......@@ -46,7 +46,6 @@ export interface IProductConfiguration {
readonly extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; };
readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; };
readonly extensionKeywords: { [extension: string]: readonly string[]; };
readonly extensionAllowedBadgeProviders: readonly string[];
readonly extensionAllowedProposedApi: readonly string[];
readonly keymapExtensionTips: readonly string[];
readonly crashReporter: {
......
......@@ -9,6 +9,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
export interface IRemoteAgentEnvironment {
pid: number;
connectionToken: string;
appRoot: URI;
appSettingsHome: URI;
settingsPath: URI;
......@@ -24,4 +25,4 @@ export interface IRemoteAgentEnvironment {
export interface RemoteAgentConnectionContext {
remoteAuthority: string;
clientId: string;
}
\ No newline at end of file
}
......@@ -6,6 +6,7 @@
import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ipcRenderer as ipc } from 'electron';
import * as errors from 'vs/base/common/errors';
import { RemoteAuthorities } from 'vs/base/common/network';
class PendingResolveAuthorityRequest {
constructor(
......@@ -50,6 +51,7 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
if (this._resolveAuthorityRequests[resolvedAuthority.authority]) {
let request = this._resolveAuthorityRequests[resolvedAuthority.authority];
ipc.send('vscode:remoteAuthorityResolved', resolvedAuthority);
RemoteAuthorities.set(resolvedAuthority.authority, resolvedAuthority.host, resolvedAuthority.port);
request.resolve({ authority: resolvedAuthority, options });
}
}
......
......@@ -96,12 +96,12 @@ export interface IWindowsService {
_serviceBrand: any;
onWindowOpen: Event<number>;
onWindowFocus: Event<number>;
onWindowBlur: Event<number>;
onWindowMaximize: Event<number>;
onWindowUnmaximize: Event<number>;
onRecentlyOpenedChange: Event<void>;
readonly onWindowOpen: Event<number>;
readonly onWindowFocus: Event<number>;
readonly onWindowBlur: Event<number>;
readonly onWindowMaximize: Event<number>;
readonly onWindowUnmaximize: Event<number>;
readonly onRecentlyOpenedChange: Event<void>;
// Dialogs
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
......
......@@ -12,14 +12,14 @@ import { IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/commo
export class WindowsChannel implements IServerChannel {
private onWindowOpen: Event<number>;
private onWindowFocus: Event<number>;
private onWindowBlur: Event<number>;
private onWindowMaximize: Event<number>;
private onWindowUnmaximize: Event<number>;
private onRecentlyOpenedChange: Event<void>;
private readonly onWindowOpen: Event<number>;
private readonly onWindowFocus: Event<number>;
private readonly onWindowBlur: Event<number>;
private readonly onWindowMaximize: Event<number>;
private readonly onWindowUnmaximize: Event<number>;
private readonly onRecentlyOpenedChange: Event<void>;
constructor(private service: IWindowsService) {
constructor(private readonly service: IWindowsService) {
this.onWindowOpen = Event.buffer(service.onWindowOpen, true);
this.onWindowFocus = Event.buffer(service.onWindowFocus, true);
this.onWindowBlur = Event.buffer(service.onWindowBlur, true);
......@@ -120,4 +120,4 @@ export class WindowsChannel implements IServerChannel {
throw new Error(`Call not found: ${command}`);
}
}
\ No newline at end of file
}
......@@ -1161,11 +1161,11 @@ declare module 'vscode' {
/**
* Content security policy source for webview resources.
*
* This is origin used in a content security policy rule:
* This is the origin that should be used in a content security policy rule:
*
* ```
* img-src https: ${webview.cspSource} ...;
* ````
* ```
*/
readonly cspSource: string;
}
......
......@@ -90,7 +90,6 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
const webview = this._webviewService.createWebview('' + handle, {
enableFindWidget: false,
allowSvgs: false,
extension: { id: extensionId, location: URI.revive(extensionLocation) }
}, {
allowScripts: options.enableScripts,
......
......@@ -151,7 +151,7 @@ const viewsContribution: IJSONSchema = {
default: []
},
'remote': {
description: localize('views.remote', "Contributes views to Remote container in the Activity bar"),
description: localize('views.remote', "Contributes views to Remote container in the Activity bar. To contribute to this container, enableProposedApi needs to be turned on"),
type: 'array',
items: nestableViewDescriptor,
default: []
......@@ -387,6 +387,11 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
return;
}
if (entry.key === 'remote' && !extension.description.enableProposedApi) {
collector.warn(localize('ViewContainerRequiresProposedAPI', "View container '{0}' requires 'enableProposedApi' turned on to be added to 'Remote'.", entry.key));
return;
}
const viewContainer = this.getViewContainer(entry.key);
if (!viewContainer) {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
......
......@@ -40,6 +40,7 @@ import { BrowserStorageService } from 'vs/platform/storage/browser/storageServic
import { IStorageService } from 'vs/platform/storage/common/storage';
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
class CodeRendererMain extends Disposable {
......@@ -82,6 +83,11 @@ class CodeRendererMain extends Disposable {
}));
this._register(workbench.onShutdown(() => this.dispose()));
// Driver
if (this.configuration.driver) {
registerWindowDriver().then(d => this._register(d));
}
// Startup
workbench.startup();
}
......
......@@ -29,13 +29,14 @@ export abstract class SimpleFindWidget extends Widget {
private readonly _findInput: FindInput;
private readonly _domNode: HTMLElement;
private readonly _innerDomNode: HTMLElement;
private _isVisible: boolean = false;
private readonly _focusTracker: dom.IFocusTracker;
private readonly _findInputFocusTracker: dom.IFocusTracker;
private readonly _updateHistoryDelayer: Delayer<void>;
private prevBtn: SimpleButton;
private nextBtn: SimpleButton;
private foundMatch: boolean;
private readonly prevBtn: SimpleButton;
private readonly nextBtn: SimpleButton;
private _isVisible: boolean = false;
private foundMatch: boolean = false;
constructor(
@IContextViewService private readonly _contextViewService: IContextViewService,
......
......@@ -572,9 +572,7 @@ export class ExtensionEditor extends BaseEditor {
{
enableFindWidget: true,
},
{
svgWhiteList: this.extensionsWorkbenchService.allowedBadgeProviders,
});
{});
webviewElement.mountTo(template.content);
this.contentDisposables.add(webviewElement.onDidFocus(() => this.fireOnDidFocus()));
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, webviewElement);
......
......@@ -484,7 +484,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
private readonly _onChange: Emitter<IExtension | undefined> = new Emitter<IExtension | undefined>();
get onChange(): Event<IExtension | undefined> { return this._onChange.event; }
private _extensionAllowedBadgeProviders: string[] | undefined;
private installing: IExtension[] = [];
constructor(
......@@ -1020,13 +1019,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return changed;
}
get allowedBadgeProviders(): string[] {
if (!this._extensionAllowedBadgeProviders) {
this._extensionAllowedBadgeProviders = (this.productService.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase());
}
return this._extensionAllowedBadgeProviders;
}
private _activityCallBack: (() => void) | null = null;
private updateActivity(): void {
if ((this.localExtensions && this.localExtensions.local.some(e => e.state === ExtensionState.Installing || e.state === ExtensionState.Uninstalling))
......
......@@ -91,7 +91,6 @@ export interface IExtensionsWorkbenchService {
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>;
open(extension: IExtension, sideByside?: boolean): Promise<any>;
checkForUpdates(): Promise<void>;
allowedBadgeProviders: string[];
}
export const ConfigurationKey = 'extensions';
......
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.3232L5.96154 13.3232L5.17083 13.2874L1.82083 8.5174L2.63918 7.94268L5.617 12.1827L13.6685 2.67688L14.4315 3.3232Z" fill="#C5C5C5"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.3232L5.96154 13.3232L5.17083 13.2874L1.82083 8.5174L2.63918 7.94268L5.617 12.1827L13.6685 2.67688L14.4315 3.3232Z" fill="#424242"/>
</svg>
......@@ -148,7 +148,7 @@ export class ExplorerItem {
return this === this.root;
}
static create(raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: URI[]): ExplorerItem {
static create(raw: IFileStat, parent: ExplorerItem | undefined, resolveTo?: readonly URI[]): ExplorerItem {
const stat = new ExplorerItem(raw.resource, parent, raw.isDirectory, raw.isSymbolicLink, raw.isReadonly, raw.name, raw.mtime);
// Recursively add children if present
......
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#C5C5C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.3232L5.96154 13.3232L5.17083 13.2874L1.82083 8.5174L2.63918 7.94268L5.617 12.1827L13.6685 2.67688L14.4315 3.3232Z" fill="#C5C5C5"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 3.76345L5.80687 11.9351L5.08584 11.8927L1 7.29614L1.76345 6.61752L5.50997 10.8324L14.3214 3L15 3.76345Z" fill="#424242"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4315 3.3232L5.96154 13.3232L5.17083 13.2874L1.82083 8.5174L2.63918 7.94268L5.617 12.1827L13.6685 2.67688L14.4315 3.3232Z" fill="#424242"/>
</svg>
......@@ -386,6 +386,10 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel {
}
private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser<HelpInformation>, helpInformation: HelpInformation[]) {
if (!extension.description.enableProposedApi) {
return;
}
if (!extension.value.documentation && !extension.value.feedback && !extension.value.getStarted && !extension.value.issues) {
return;
}
......
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="2.5" width="11" height="11" stroke="#C5C5C5" stroke-linejoin="bevel"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4167 6.5C13.4167 6.54043 13.4162 6.58073 13.4151 6.6209C13.7562 6.80943 14.073 7.03667 14.3594 7.29667C14.3972 7.03657 14.4167 6.77057 14.4167 6.5C14.4167 3.46243 11.9543 1 8.9167 1C5.87913 1 3.41669 3.46243 3.41669 6.5C3.41669 7.89885 3.93892 9.17573 4.79905 10.1463L1 13.8386L1.75006 14.5L5.52761 10.8321C5.67974 10.9512 5.8383 11.0626 6.00269 11.1655C6.0009 11.1105 6 11.0554 6 11C6 10.6605 6.03384 10.3288 6.09834 10.0083C5.07293 9.18351 4.41669 7.91839 4.41669 6.5C4.41669 4.01472 6.43141 2 8.9167 2C11.402 2 13.4167 4.01472 13.4167 6.5ZM11 14C11.6479 14 12.2478 13.7946 12.7382 13.4454L8.55459 9.26177C8.20537 9.75217 7.99999 10.3521 7.99999 11C7.99999 12.6569 9.34313 14 11 14ZM9.26168 8.55465L13.4453 12.7383C13.7946 12.2479 14 11.6479 14 11C14 9.34315 12.6568 8 11 8C10.3521 8 9.7521 8.20541 9.26168 8.55465ZM11 15C13.2091 15 15 13.2091 15 11C15 8.79086 13.2091 7 11 7C8.79085 7 6.99999 8.79086 6.99999 11C6.99999 13.2091 8.79085 15 11 15Z" fill="#C5C5C5"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="2.5" width="11" height="11" stroke="white" stroke-linejoin="bevel"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4167 6.5C13.4167 6.54043 13.4162 6.58073 13.4151 6.6209C13.7562 6.80943 14.073 7.03667 14.3594 7.29667C14.3972 7.03657 14.4167 6.77057 14.4167 6.5C14.4167 3.46243 11.9543 1 8.9167 1C5.87913 1 3.41669 3.46243 3.41669 6.5C3.41669 7.89885 3.93892 9.17573 4.79905 10.1463L1 13.8386L1.75006 14.5L5.52761 10.8321C5.67974 10.9512 5.8383 11.0626 6.00269 11.1655C6.0009 11.1105 6 11.0554 6 11C6 10.6605 6.03384 10.3288 6.09834 10.0083C5.07293 9.18351 4.41669 7.91839 4.41669 6.5C4.41669 4.01472 6.43141 2 8.9167 2C11.402 2 13.4167 4.01472 13.4167 6.5ZM11 14C11.6479 14 12.2478 13.7946 12.7382 13.4454L8.55459 9.26177C8.20537 9.75217 7.99999 10.3521 7.99999 11C7.99999 12.6569 9.34313 14 11 14ZM9.26168 8.55465L13.4453 12.7383C13.7946 12.2479 14 11.6479 14 11C14 9.34315 12.6568 8 11 8C10.3521 8 9.7521 8.20541 9.26168 8.55465ZM11 15C13.2091 15 15 13.2091 15 11C15 8.79086 13.2091 7 11 7C8.79085 7 6.99999 8.79086 6.99999 11C6.99999 13.2091 8.79085 15 11 15Z" fill="white"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="2.5" width="11" height="11" stroke="#424242" stroke-linejoin="bevel"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.4167 6.5C13.4167 6.54043 13.4162 6.58073 13.4151 6.6209C13.7562 6.80943 14.073 7.03667 14.3594 7.29667C14.3972 7.03657 14.4167 6.77057 14.4167 6.5C14.4167 3.46243 11.9543 1 8.9167 1C5.87913 1 3.41669 3.46243 3.41669 6.5C3.41669 7.89885 3.93892 9.17573 4.79905 10.1463L1 13.8386L1.75006 14.5L5.52761 10.8321C5.67974 10.9512 5.8383 11.0626 6.00269 11.1655C6.0009 11.1105 6 11.0554 6 11C6 10.6605 6.03384 10.3288 6.09834 10.0083C5.07293 9.18351 4.41669 7.91839 4.41669 6.5C4.41669 4.01472 6.43141 2 8.9167 2C11.402 2 13.4167 4.01472 13.4167 6.5ZM11 14C11.6479 14 12.2478 13.7946 12.7382 13.4454L8.55459 9.26177C8.20537 9.75217 7.99999 10.3521 7.99999 11C7.99999 12.6569 9.34313 14 11 14ZM9.26168 8.55465L13.4453 12.7383C13.7946 12.2479 14 11.6479 14 11C14 9.34315 12.6568 8 11 8C10.3521 8 9.7521 8.20541 9.26168 8.55465ZM11 15C13.2091 15 15 13.2091 15 11C15 8.79086 13.2091 7 11 7C8.79085 7 6.99999 8.79086 6.99999 11C6.99999 13.2091 8.79085 15 11 15Z" fill="#424242"/>
</svg>
......@@ -285,6 +285,12 @@
applyStyles(newDocument, newDocument.body);
// Check for CSP
const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]');
if (!csp) {
host.postMessage('no-csp-found');
}
// set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off
// and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden
return '<!DOCTYPE html>\n' + newDocument.documentElement.outerHTML;
......
......@@ -244,7 +244,6 @@ export class WebviewEditorService implements IWebviewEditorService {
private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) {
return this._webviewService.createWebviewEditorOverlay(id, {
allowSvgs: true,
extension: extension,
enableFindWidget: options.enableFindWidget,
retainContextWhenHidden: options.retainContextWhenHidden
......
......@@ -213,7 +213,7 @@ export class IFrameWebview extends Disposable implements Webview {
}
}
initialScrollProgress: number;
initialScrollProgress: number = 0;
private readonly _onDidFocus = this._register(new Emitter<void>());
public readonly onDidFocus = this._onDidFocus.event;
......
......@@ -41,7 +41,6 @@ export interface IWebviewService {
export const WebviewResourceScheme = 'vscode-resource';
export interface WebviewOptions {
readonly allowSvgs?: boolean;
readonly extension?: {
readonly location: URI;
readonly id?: ExtensionIdentifier;
......@@ -53,7 +52,6 @@ export interface WebviewOptions {
export interface WebviewContentOptions {
readonly allowScripts?: boolean;
readonly svgWhiteList?: string[];
readonly localResourceRoots?: ReadonlyArray<URI>;
readonly portMapping?: ReadonlyArray<modes.IWebviewPortMapping>;
readonly enableCommandUris?: boolean;
......
......@@ -9,13 +9,14 @@ import { Emitter, Event } from 'vs/base/common/event';
import { once } from 'vs/base/common/functional';
import { Disposable } from 'vs/base/common/lifecycle';
import { isMacintosh } from 'vs/base/common/platform';
import { endsWith } from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping';
import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing';
......@@ -135,51 +136,6 @@ class WebviewPortMappingProvider extends Disposable {
}
}
class SvgBlocker extends Disposable {
private readonly _onDidBlockSvg = this._register(new Emitter<void>());
public readonly onDidBlockSvg = this._onDidBlockSvg.event;
constructor(
session: WebviewSession,
private readonly _options: WebviewContentOptions,
) {
super();
session.onBeforeRequest(async (details) => {
if (details.url.indexOf('.svg') > 0) {
const uri = URI.parse(details.url);
if (uri && !uri.scheme.match(/file/i) && endsWith(uri.path, '.svg') && !this.isAllowedSvg(uri)) {
this._onDidBlockSvg.fire();
return { cancel: true };
}
}
return undefined;
});
session.onHeadersReceived((details) => {
const headers: any = details.responseHeaders;
const contentType: string[] = headers['content-type'] || headers['Content-Type'];
if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) {
const uri = URI.parse(details.url);
if (uri && !this.isAllowedSvg(uri)) {
this._onDidBlockSvg.fire();
return { cancel: true };
}
}
return undefined;
});
}
private isAllowedSvg(uri: URI): boolean {
if (this._options.svgWhiteList) {
return this._options.svgWhiteList.indexOf(uri.authority.toLowerCase()) >= 0;
}
return false;
}
}
class WebviewKeyboardHandler extends Disposable {
private _ignoreMenuShortcut = false;
......@@ -284,6 +240,8 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
@IFileService fileService: IFileService,
@ITunnelService tunnelService: ITunnelService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IEnvironmentService private readonly _environementService: IEnvironmentService,
) {
super();
this.content = {
......@@ -331,11 +289,6 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
tunnelService,
));
if (!this._options.allowSvgs) {
const svgBlocker = this._register(new SvgBlocker(session, this.content.options));
svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg());
}
this._register(new WebviewKeyboardHandler(this._webview));
this._register(addDisposableListener(this._webview, 'console-message', function (e: { level: number; message: string; line: number; sourceId: string; }) {
......@@ -412,6 +365,10 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
case 'did-blur':
this.handleFocusChange(false);
return;
case 'no-csp-found':
this.handleNoCspFound();
return;
}
}));
this._register(addDisposableListener(this._webview, 'devtools-opened', () => {
......@@ -546,14 +503,34 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
}
}
public sendMessage(data: any): void {
this._send('message', data);
private _hasAlertedAboutMissingCsp = false;
private handleNoCspFound(): void {
if (this._hasAlertedAboutMissingCsp) {
return;
}
this._hasAlertedAboutMissingCsp = true;
if (this._options.extension && this._options.extension.id) {
if (this._environementService.isExtensionDevelopment) {
console.warn(`${this._options.extension.id.value} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
}
type TelemetryClassification = {
extension?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }
};
type TelemetryData = {
extension?: string,
};
this._telemetryService.publicLog2<TelemetryData, TelemetryClassification>('webviewMissingCsp', {
extension: this._options.extension.id.value
});
}
}
private onDidBlockSvg() {
this.sendMessage({
name: 'vscode-did-block-svg'
});
public sendMessage(data: any): void {
this._send('message', data);
}
private style(theme: ITheme): void {
......
......@@ -203,7 +203,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
}
private getConnectionToken(str: string): string | undefined {
const m = str.match(/[#&]tkn=([^&]+)/);
const m = str.match(/[#&?]tkn=([^&]+)/);
return m ? m[1] : undefined;
}
}
......@@ -9,6 +9,7 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
import { RemoteAuthorities } from 'vs/base/common/network';
export interface IGetEnvironmentDataArguments {
language: string;
......@@ -18,6 +19,7 @@ export interface IGetEnvironmentDataArguments {
export interface IRemoteAgentEnvironmentDTO {
pid: number;
connectionToken: string;
appRoot: UriComponents;
appSettingsHome: UriComponents;
settingsPath: UriComponents;
......@@ -43,8 +45,11 @@ export class RemoteExtensionEnvironmentChannelClient {
const data = await this.channel.call<IRemoteAgentEnvironmentDTO>('getEnvironmentData', args);
RemoteAuthorities.setConnectionToken(remoteAuthority, data.connectionToken);
return {
pid: data.pid,
connectionToken: data.connectionToken,
appRoot: URI.revive(data.appRoot),
appSettingsHome: URI.revive(data.appSettingsHome),
settingsPath: URI.revive(data.settingsPath),
......
......@@ -1340,12 +1340,12 @@ export class TestWindowsService implements IWindowsService {
public windowCount = 1;
onWindowOpen: Event<number>;
onWindowFocus: Event<number>;
onWindowBlur: Event<number>;
onWindowMaximize: Event<number>;
onWindowUnmaximize: Event<number>;
onRecentlyOpenedChange: Event<void>;
readonly onWindowOpen: Event<number> = Event.None;
readonly onWindowFocus: Event<number> = Event.None;
readonly onWindowBlur: Event<number> = Event.None;
readonly onWindowMaximize: Event<number> = Event.None;
readonly onWindowUnmaximize: Event<number> = Event.None;
readonly onRecentlyOpenedChange: Event<void> = Event.None;
isFocused(_windowId: number): Promise<boolean> {
return Promise.resolve(false);
......
......@@ -18,6 +18,7 @@
"@types/mocha": "2.2.41",
"@types/ncp": "2.0.1",
"@types/node": "^10.14.8",
"@types/puppeteer": "^1.19.0",
"@types/rimraf": "2.0.2",
"@types/webdriverio": "4.6.1",
"concurrently": "^3.5.1",
......
......@@ -124,7 +124,9 @@ export class Application {
verbose: this.options.verbose,
log: this.options.log,
extraArgs,
remote: this.options.remote
remote: this.options.remote,
web: this.options.web,
headless: this.options.headless
});
this._workbench = new Workbench(this._code, this.userDataPath);
......
......@@ -34,4 +34,4 @@ export function setup() {
await app.workbench.settingsEditor.clearUserSettings();
});
});
}
\ No newline at end of file
}
......@@ -30,7 +30,7 @@ export class SettingsEditor {
async clearUserSettings(): Promise<void> {
const settingsPath = path.join(this.userDataPath, 'User', 'settings.json');
await new Promise((c, e) => fs.writeFile(settingsPath, '{}', 'utf8', err => err ? e(err) : c()));
await new Promise((c, e) => fs.writeFile(settingsPath, '{\n}', 'utf8', err => err ? e(err) : c()));
await this.openSettings();
await this.editor.waitForEditorContents('settings.json', c => c === '{}');
......@@ -39,4 +39,4 @@ export class SettingsEditor {
private async openSettings(): Promise<void> {
await this.quickopen.runCommand('Preferences: Open Settings (JSON)');
}
}
\ No newline at end of file
}
......@@ -51,7 +51,9 @@ const opts = minimist(args, {
],
boolean: [
'verbose',
'remote'
'remote',
'web',
'headless'
],
default: {
verbose: false
......@@ -132,7 +134,7 @@ if (testCodePath) {
process.env.VSCODE_CLI = '1';
}
if (!fs.existsSync(electronPath || '')) {
if (!opts.web && !fs.existsSync(electronPath || '')) {
fail(`Can't find Code at ${electronPath}.`);
}
......@@ -211,7 +213,9 @@ function createOptions(): ApplicationOptions {
verbose: opts.verbose,
log,
screenshotsPath,
remote: opts.remote
remote: opts.remote,
web: opts.web,
headless: opts.headless
};
}
......@@ -234,12 +238,14 @@ after(async function () {
await new Promise((c, e) => rimraf(testDataPath, { maxBusyTries: 10 }, err => err ? e(err) : c()));
});
setupDataMigrationTests(stableCodePath, testDataPath);
if (!opts.web) {
setupDataMigrationTests(stableCodePath, testDataPath);
}
describe('Running Code', () => {
before(async function () {
const app = new Application(this.defaultOptions);
await app!.start();
await app!.start(opts.web ? false : undefined);
this.app = app;
});
......@@ -268,19 +274,21 @@ describe('Running Code', () => {
});
}
setupDataLossTests();
if (!opts.web) { setupDataLossTests(); }
setupDataExplorerTests();
setupDataPreferencesTests();
if (!opts.web) { setupDataPreferencesTests(); }
setupDataSearchTests();
setupDataCSSTests();
setupDataEditorTests();
setupDataDebugTests();
if (!opts.web) { setupDataDebugTests(); }
setupDataGitTests();
setupDataStatusbarTests();
setupDataExtensionTests();
setupTerminalTests();
setupDataMultirootTests();
if (!opts.web) { setupDataMultirootTests(); }
setupDataLocalizationTests();
});
setupLaunchTests();
\ No newline at end of file
if (!opts.web) {
setupLaunchTests();
}
......@@ -9,7 +9,8 @@ import * as os from 'os';
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import { tmpName } from 'tmp';
import { IDriver, connect as connectDriver, IDisposable, IElement, Thenable } from './driver';
import { IDriver, connect as connectElectronDriver, IDisposable, IElement, Thenable } from './driver';
import { connect as connectPuppeteerDriver, launch } from './puppeteerDriver';
import { Logger } from '../logger';
import { ncp } from 'ncp';
import { URI } from 'vscode-uri';
......@@ -62,7 +63,7 @@ function getBuildOutPath(root: string): string {
}
}
async function connect(child: cp.ChildProcess, outPath: string, handlePath: string, logger: Logger): Promise<Code> {
async function connect(connectDriver: typeof connectElectronDriver, child: cp.ChildProcess | undefined, outPath: string, handlePath: string, logger: Logger): Promise<Code> {
let errCount = 0;
while (true) {
......@@ -71,7 +72,9 @@ async function connect(child: cp.ChildProcess, outPath: string, handlePath: stri
return new Code(client, driver, logger);
} catch (err) {
if (++errCount > 50) {
child.kill();
if (child) {
child.kill();
}
throw err;
}
......@@ -94,7 +97,12 @@ export interface SpawnOptions {
verbose?: boolean;
extraArgs?: string[];
log?: string;
/** Run in the test resolver */
remote?: boolean;
/** Run in the web */
web?: boolean;
/** Run in headless mode (only applies when web is true) */
headless?: boolean;
}
async function createDriverHandle(): Promise<string> {
......@@ -161,14 +169,20 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
args.push(...options.extraArgs);
}
const spawnOptions: cp.SpawnOptions = { env };
const child = cp.spawn(electronPath, args, spawnOptions);
instances.add(child);
child.once('exit', () => instances.delete(child));
let child: cp.ChildProcess | undefined;
let connectDriver: typeof connectElectronDriver;
return connect(child, outPath, handle, options.logger);
if (options.web) {
await launch(args);
connectDriver = connectPuppeteerDriver.bind(connectPuppeteerDriver, !!options.headless);
} else {
const spawnOptions: cp.SpawnOptions = { env };
child = cp.spawn(electronPath, args, spawnOptions);
instances.add(child);
child.once('exit', () => instances.delete(child!));
connectDriver = connectElectronDriver;
}
return connect(connectDriver, child, outPath, handle, options.logger);
}
async function poll<T>(
......@@ -364,4 +378,4 @@ export function findElements(element: IElement, fn: (element: IElement) => boole
}
return result;
}
\ No newline at end of file
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as puppeteer from 'puppeteer';
import { ChildProcess, spawn } from 'child_process';
import { join } from 'path';
import { mkdir } from 'fs';
import { promisify } from 'util';
const width = 1200;
const height = 800;
const vscodeToPuppeteerKey = {
cmd: 'Meta',
ctrl: 'Control',
shift: 'Shift',
enter: 'Enter',
escape: 'Escape',
right: 'ArrowRight',
up: 'ArrowUp',
down: 'ArrowDown',
left: 'ArrowLeft',
home: 'Home'
};
function buildDriver(browser: puppeteer.Browser, page: puppeteer.Page): IDriver {
const driver = {
_serviceBrand: undefined,
getWindowIds: () => {
return Promise.resolve([1]);
},
capturePage: () => Promise.resolve(''),
reloadWindow: (windowId) => Promise.resolve(),
exitApplication: () => browser.close(),
dispatchKeybinding: async (windowId, keybinding) => {
const chords = keybinding.split(' ');
for (let i = 0; i < chords.length; i++) {
const chord = chords[i];
if (i > 0) {
await timeout(100);
}
const keys = chord.split('+');
const keysDown: string[] = [];
for (let i = 0; i < keys.length; i++) {
if (keys[i] in vscodeToPuppeteerKey) {
keys[i] = vscodeToPuppeteerKey[keys[i]];
}
await page.keyboard.down(keys[i]);
keysDown.push(keys[i]);
}
while (keysDown.length > 0) {
await page.keyboard.up(keysDown.pop()!);
}
}
await timeout(100);
},
click: async (windowId, selector, xoffset, yoffset) => {
const { x, y } = await driver.getElementXY(windowId, selector, xoffset, yoffset);
await page.mouse.click(x + (xoffset ? xoffset : 0), y + (yoffset ? yoffset : 0));
},
doubleClick: async (windowId, selector) => {
await driver.click(windowId, selector, 0, 0);
await timeout(60);
await driver.click(windowId, selector, 0, 0);
await timeout(100);
},
setValue: async (windowId, selector, text) => page.evaluate(`window.driver.setValue('${selector}', '${text}')`),
getTitle: (windowId) => page.evaluate(`window.driver.getTitle()`),
isActiveElement: (windowId, selector) => page.evaluate(`window.driver.isActiveElement('${selector}')`),
getElements: (windowId, selector, recursive) => page.evaluate(`window.driver.getElements('${selector}', ${recursive})`),
getElementXY: (windowId, selector, xoffset?, yoffset?) => page.evaluate(`window.driver.getElementXY('${selector}', ${xoffset}, ${yoffset})`),
typeInEditor: (windowId, selector, text) => page.evaluate(`window.driver.typeInEditor('${selector}', '${text}')`),
getTerminalBuffer: (windowId, selector) => page.evaluate(`window.driver.getTerminalBuffer('${selector}')`),
writeInTerminal: (windowId, selector, text) => page.evaluate(`window.driver.writeInTerminal('${selector}', '${text}')`)
};
return driver;
}
function timeout(ms: number): Promise<void> {
return new Promise<void>(r => setTimeout(r, ms));
}
// function runInDriver(call: string, args: (string | boolean)[]): Promise<any> {}
let args: string[] | undefined;
let server: ChildProcess | undefined;
let endpoint: string | undefined;
export async function launch(_args: string[]): Promise<void> {
args = _args;
const webUserDataDir = args.filter(e => e.includes('--user-data-dir='))[0].replace('--user-data-dir=', '');
await promisify(mkdir)(webUserDataDir);
server = spawn(join(args[0], `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`), ['--browser', 'none', '--driver', 'web', '--web-user-data-dir', webUserDataDir]);
server.stderr.on('data', e => console.log('Server stderr: ' + e));
process.on('exit', teardown);
process.on('SIGINT', teardown);
endpoint = await waitForEndpoint();
}
function teardown(): void {
if (server) {
server.kill();
server = undefined;
}
}
function waitForEndpoint(): Promise<string> {
return new Promise<string>(r => {
server!.stdout.on('data', d => {
const matches = d.toString('ascii').match(/Web UI available at (.+)/);
if (matches !== null) {
r(matches[1]);
}
});
});
}
export function connect(headless: boolean, outPath: string, handle: string): Promise<{ client: IDisposable, driver: IDriver }> {
return new Promise(async (c) => {
const browser = await puppeteer.launch({
// Run in Edge dev on macOS
// executablePath: '/Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev',
headless,
slowMo: 80,
args: [`--window-size=${width},${height}`]
});
const page = (await browser.pages())[0];
await page.setViewport({ width, height });
const endpointSplit = endpoint!.split('#');
await page.goto(`${endpointSplit[0]}?folder=${args![1]}#${endpointSplit[1]}`);
const result = {
client: { dispose: () => teardown },
driver: buildDriver(browser, page)
};
c(result);
});
}
/**
* Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise,
* and others. This API makes no assumption about what promise library is being used which
* enables reusing existing code without migrating to a specific promise implementation. Still,
* we recommend the use of native promises which are available in this editor.
*/
export interface Thenable<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
}
export interface IElement {
tagName: string;
className: string;
textContent: string;
attributes: { [name: string]: string; };
children: IElement[];
top: number;
left: number;
}
export interface IDriver {
_serviceBrand: any;
getWindowIds(): Promise<number[]>;
capturePage(windowId: number): Promise<string>;
reloadWindow(windowId: number): Promise<void>;
exitApplication(): Promise<void>;
dispatchKeybinding(windowId: number, keybinding: string): Promise<void>;
click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise<void>;
doubleClick(windowId: number, selector: string): Promise<void>;
setValue(windowId: number, selector: string, text: string): Promise<void>;
getTitle(windowId: number): Promise<string>;
isActiveElement(windowId: number, selector: string): Promise<boolean>;
getElements(windowId: number, selector: string, recursive?: boolean): Promise<IElement[]>;
getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }>;
typeInEditor(windowId: number, selector: string, text: string): Promise<void>;
getTerminalBuffer(windowId: number, selector: string): Promise<string[]>;
writeInTerminal(windowId: number, selector: string, text: string): Promise<void>;
}
export interface IDisposable {
dispose(): void;
}
......@@ -7,7 +7,7 @@ const fs = require('fs');
const path = require('path');
const root = path.dirname(path.dirname(path.dirname(__dirname)));
const driverPath = path.join(root, 'src/vs/platform/driver/node/driver.ts');
const driverPath = path.join(root, 'src/vs/platform/driver/common/driver.ts');
let contents = fs.readFileSync(driverPath, 'utf8');
contents = /\/\/\*START([\s\S]*)\/\/\*END/mi.exec(contents)[1].trim();
......@@ -47,4 +47,4 @@ export function connect(outPath: string, handle: string): Promise<{ client: IDis
const srcPath = path.join(path.dirname(__dirname), 'src/vscode');
const outDriverPath = path.join(srcPath, 'driver.d.ts');
fs.writeFileSync(outDriverPath, contents);
\ No newline at end of file
fs.writeFileSync(outDriverPath, contents);
......@@ -54,6 +54,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9"
integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==
"@types/puppeteer@^1.19.0":
version "1.19.0"
resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.19.0.tgz#59f0050bae019cee7c3af2bb840a25892a3078b6"
integrity sha512-Db9LWOuTm2bR/qgPE7PQCmnsCQ6flHdULuIDWTks8YdQ/SGHKg5WGWG54gl0734NDKCTF5MbqAp2qWuvBiyQ3Q==
dependencies:
"@types/node" "*"
"@types/rimraf@2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e"
......
......@@ -1832,7 +1832,7 @@ concat-stream@1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concat-stream@^1.5.0, concat-stream@^1.6.0:
concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
......@@ -2193,14 +2193,14 @@ debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3:
dependencies:
ms "2.0.0"
debug@3.1.0, debug@^3.1.0:
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.2.6:
debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
......@@ -3135,6 +3135,16 @@ extract-zip@^1.6.5:
mkdirp "0.5.0"
yauzl "2.4.1"
extract-zip@^1.6.6:
version "1.6.7"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
dependencies:
concat-stream "1.6.2"
debug "2.6.9"
mkdirp "0.5.1"
yauzl "2.4.1"
extsprintf@1.3.0, extsprintf@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
......@@ -5802,6 +5812,11 @@ mime@^1.4.1, mime@^1.6.0:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.0.3:
version "2.4.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
......@@ -7243,7 +7258,7 @@ progress@^1.1.8:
resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
progress@^2.0.0:
progress@^2.0.0, progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
......@@ -7266,6 +7281,11 @@ proxy-addr@~2.0.2:
forwarded "~0.1.2"
ipaddr.js "1.5.2"
proxy-from-env@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
......@@ -7348,6 +7368,20 @@ punycode@^2.1.0:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@^1.19.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea"
integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==
dependencies:
debug "^4.1.0"
extract-zip "^1.6.6"
https-proxy-agent "^2.2.1"
mime "^2.0.3"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^2.6.1"
ws "^6.1.0"
q@^1.0.1, q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
......@@ -9884,6 +9918,13 @@ ws@^3.3.3:
safe-buffer "~5.1.0"
ultron "~1.1.0"
ws@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
dependencies:
async-limiter "~1.0.0"
xml-name-validator@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-1.0.0.tgz#dcf82ee092322951ef8cc1ba596c9cbfd14a83f1"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册