Skip to content

Commit

Permalink
feat(Testing API): Migration of the PluginExt part of the VS Code Tes…
Browse files Browse the repository at this point in the history
…t API

Project lead: Kevin Clapperton
Developers: Zakaria Diabi, Mathieu Bussières
Testers: Kevin Clapperton, Théo St-Denis

Signed-off-by: Zakaria Diabi  <[email protected]>
Signed-off-by: Mathieu Bussières <[email protected]>
Signed-off-by: Théo St-Denis <[email protected]>
Signed-off-by: Kevin Clapperton <[email protected]>
  • Loading branch information
D-Zaq authored and KevinClapperton committed May 8, 2023
1 parent 9dd0921 commit 2789146
Show file tree
Hide file tree
Showing 43 changed files with 8,011 additions and 13 deletions.
22 changes: 22 additions & 0 deletions packages/core/src/common/cancellation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import { Event, Emitter } from './event';
import { isBoolean, isObject } from './types';
import { Disposable } from './disposable';

export interface CancellationToken {
readonly isCancellationRequested: boolean;
Expand Down Expand Up @@ -93,11 +94,23 @@ class MutableToken implements CancellationToken {
}
return this._emitter.event;
}

public dispose(): void {
if (this._emitter) {
this._emitter.dispose();
this._emitter = undefined;
}
}
}

export class CancellationTokenSource {

private _token: CancellationToken;
private _parentListener?: Disposable = undefined;

constructor(parent?: CancellationToken) {
this._parentListener = parent && parent.onCancellationRequested(this.cancel, this);
}

get token(): CancellationToken {
if (!this._token) {
Expand All @@ -121,6 +134,15 @@ export class CancellationTokenSource {

dispose(): void {
this.cancel();
this._parentListener?.dispose();
if (!this._token) {
// ensure to initialize with an empty token if we had none
this._token = CancellationToken.None;

} else if (this._token instanceof MutableToken) {
// actually dispose
this._token.dispose();
}
}
}

Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/common/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ export namespace Event {
set maxListeners(maxListeners: number) { }
});

/**
* Given an event, returns another event which only fires once.
*/
export function once<T>(event: Event<T>): Event<T> {
return (listener, thisArgs = undefined, disposables?) => {
// we need this, in case the event fires during the listener call
let didFire = false;
let result: Disposable | undefined = undefined;
result = event(e => {
if (didFire) {
return;
} else if (result) {
result.dispose();
} else {
didFire = true;
}

return listener.call(thisArgs, e);
}, undefined, disposables);

if (didFire) {
result.dispose();
}

return result;
};
}

export function toPromise<T>(event: Event<T>): Promise<T> {
return new Promise(resolve => once(event)(resolve));
}

/**
* Given an event and a `map` function, returns another event which maps each element
* through the mapping function.
Expand Down
85 changes: 85 additions & 0 deletions packages/core/src/common/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// *****************************************************************************
// Copyright (C) 2023 Mathieu Bussieres and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation and others. All rights reserved.
* Licensed under the MIT License. See https://github.com/Microsoft/vscode/blob/master/LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

// based on https://github.com/microsoft/vscode/blob/1.72.2/src/vs/base/common/hash.ts

/**
* Return a hash value for an object.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function hash(obj: any): number {
return doHash(obj, 0);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function doHash(obj: any, hashVal: number): number {
switch (typeof obj) {
case 'object':
// eslint-disable-next-line no-null/no-null
if (obj === null) {
return numberHash(349, hashVal);
} else if (Array.isArray(obj)) {
return arrayHash(obj, hashVal);
}
return objectHash(obj, hashVal);
case 'string':
return stringHash(obj, hashVal);
case 'boolean':
return booleanHash(obj, hashVal);
case 'number':
return numberHash(obj, hashVal);
case 'undefined':
return numberHash(937, hashVal);
default:
return numberHash(617, hashVal);
}
}

export function numberHash(val: number, initialHashVal: number): number {
return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32
}

function booleanHash(b: boolean, initialHashVal: number): number {
return numberHash(b ? 433 : 863, initialHashVal);
}

export function stringHash(s: string, hashVal: number): number {
hashVal = numberHash(149417, hashVal);
for (let i = 0, length = s.length; i < length; i++) {
hashVal = numberHash(s.charCodeAt(i), hashVal);
}
return hashVal;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function arrayHash(arr: any[], initialHashVal: number): number {
initialHashVal = numberHash(104579, initialHashVal);
return arr.reduce((hashVal, item) => doHash(item, hashVal), initialHashVal);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function objectHash(obj: any, initialHashVal: number): number {
initialHashVal = numberHash(181387, initialHashVal);
return Object.keys(obj).sort().reduce((hashVal, key) => {
hashVal = stringHash(key, hashVal);
return doHash(obj[key], hashVal);
}, initialHashVal);
}
24 changes: 24 additions & 0 deletions packages/core/src/common/markdown-rendering/markdown-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,27 @@ export function escapeMarkdownSyntaxTokens(text: string): string {
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
return text.replace(/[\\`*_{}[\]()#+\-!]/g, '\\$&');
}

// Copied from https://github.com/microsoft/vscode/blob/1.72.2/src/vs/base/common/htmlContent.ts

export function parseHrefAndDimensions(href: string): { href: string; dimensions: string[] } {
const dimensions: string[] = [];
const splitted = href.split('|').map(s => s.trim());
href = splitted[0];
const parameters = splitted[1];
if (parameters) {
const heightFromParams = /height=(\d+)/.exec(parameters);
const widthFromParams = /width=(\d+)/.exec(parameters);
const height = heightFromParams ? heightFromParams[1] : '';
const width = widthFromParams ? widthFromParams[1] : '';
const widthIsFinite = isFinite(parseInt(width));
const heightIsFinite = isFinite(parseInt(height));
if (widthIsFinite) {
dimensions.push(`width="${width}"`);
}
if (heightIsFinite) {
dimensions.push(`height="${height}"`);
}
}
return { href, dimensions };
}
53 changes: 52 additions & 1 deletion packages/core/src/common/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { isObject } from './types';
import { isObject, isUndefinedOrNull } from './types';

export function deepClone<T>(obj: T): T {
if (!isObject(obj)) {
Expand Down Expand Up @@ -70,3 +70,54 @@ export function notEmpty<T>(arg: T | undefined | null): arg is T {
export function isEmpty(arg: Object): boolean {
return Object.keys(arg).length === 0 && arg.constructor === Object;
}

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation and others. All rights reserved.
* Licensed under the MIT License. See https://github.com/Microsoft/vscode/blob/master/LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

// Copied from https://github.com/microsoft/vscode/blob/1.72.2/src/vs/base/common/objects.ts

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function cloneAndChange(obj: any, changer: (orig: any) => any): any {
return _cloneAndChange(obj, changer, new Set());
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set<any>): any {
if (isUndefinedOrNull(obj)) {
return obj;
}

const changed = changer(obj);
if (typeof changed !== 'undefined') {
return changed;
}

if (Array.isArray(obj)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const r1: any[] = [];
for (const e of obj) {
r1.push(_cloneAndChange(e, changer, seen));
}
return r1;
}

if (isObject(obj)) {
if (seen.has(obj)) {
throw new Error('Cannot clone recursive data-structure');
}
seen.add(obj);
const r2 = {};
for (const i2 in obj) {
if (_hasOwnProperty.call(obj, i2)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(r2 as any)[i2] = _cloneAndChange(obj[i2], changer, seen);
}
}
seen.delete(obj);
return r2;
}

return obj;
}
11 changes: 11 additions & 0 deletions packages/core/src/common/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,14 @@ export function compareSubstringIgnoreCase(a: string, b: string, aStart: number

return 0;
}

// Copied from https://github.com/microsoft/vscode/blob/1.72.2/src/vs/base/common/strings.ts

export function regExpFlags(regexp: RegExp): string {
return (regexp.global ? 'g' : '')
+ (regexp.ignoreCase ? 'i' : '')
+ (regexp.multiline ? 'm' : '')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ((regexp as any /* standalone editor compilation */).unicode ? 'u' : '');
}

22 changes: 22 additions & 0 deletions packages/core/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,25 @@ export function nullToUndefined<T>(nullable: MaybeNull<T>): MaybeUndefined<T> {
export function unreachable(_never: never, message: string = 'unhandled case'): never {
throw new Error(message);
}

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation and others. All rights reserved.
* Licensed under the MIT License. See https://github.com/Microsoft/vscode/blob/master/LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

// Copied from https://github.com/microsoft/vscode/blob/1.72.2/src/vs/base/common/types.ts

/**
* @returns whether the provided parameter is defined.
*/
export function isDefined<T>(arg: T | null | undefined): arg is T {
return !isUndefinedOrNull(arg);
}

/**
* @returns whether the provided parameter is undefined or null.
*/
export function isUndefinedOrNull(obj: unknown): obj is undefined | null {
// eslint-disable-next-line no-null/no-null
return (isUndefined(obj) || obj === null);
}
Loading

0 comments on commit 2789146

Please sign in to comment.