mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 10:38:31 -05:00
Merge from vscode 2b0b9136329c181a9e381463a1f7dc3a2d105a34 (#4880)
This commit is contained in:
@@ -659,19 +659,6 @@ export class RunOnceWorker<T> extends RunOnceScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
export function nfcall(fn: Function, ...args: any[]): Promise<any>;
|
||||
export function nfcall<T>(fn: Function, ...args: any[]): Promise<T>;
|
||||
export function nfcall(fn: Function, ...args: any[]): any {
|
||||
return new Promise((c, e) => fn(...args, (err: any, result: any) => err ? e(err) : c(result)));
|
||||
}
|
||||
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): Promise<any>;
|
||||
export function ninvoke<T>(thisArg: any, fn: Function, ...args: any[]): Promise<T>;
|
||||
export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any {
|
||||
return new Promise((resolve, reject) => fn.call(thisArg, ...args, (err: any, result: any) => err ? reject(err) : resolve(result)));
|
||||
}
|
||||
|
||||
|
||||
//#region -- run on idle tricks ------------
|
||||
|
||||
export interface IdleDeadline {
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
declare var Buffer: any;
|
||||
const hasBuffer = (typeof Buffer !== 'undefined');
|
||||
|
||||
let textEncoder: TextEncoder | null;
|
||||
let textDecoder: TextDecoder | null;
|
||||
|
||||
export class VSBuffer {
|
||||
|
||||
public static alloc(byteLength: number): VSBuffer {
|
||||
@@ -21,7 +24,14 @@ export class VSBuffer {
|
||||
}
|
||||
|
||||
public static fromString(source: string): VSBuffer {
|
||||
return new VSBuffer(Buffer.from(source));
|
||||
if (hasBuffer) {
|
||||
return new VSBuffer(Buffer.from(source));
|
||||
} else {
|
||||
if (!textEncoder) {
|
||||
textEncoder = new TextEncoder();
|
||||
}
|
||||
return new VSBuffer(textEncoder.encode(source));
|
||||
}
|
||||
}
|
||||
|
||||
public static concat(buffers: VSBuffer[], totalLength?: number): VSBuffer {
|
||||
@@ -52,7 +62,14 @@ export class VSBuffer {
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.buffer.toString();
|
||||
if (hasBuffer) {
|
||||
return this.buffer.toString();
|
||||
} else {
|
||||
if (!textDecoder) {
|
||||
textDecoder = new TextDecoder();
|
||||
}
|
||||
return textDecoder.decode(this.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public slice(start?: number, end?: number): VSBuffer {
|
||||
|
||||
@@ -87,7 +87,12 @@ class MutableToken implements CancellationToken {
|
||||
|
||||
export class CancellationTokenSource {
|
||||
|
||||
private _token?: CancellationToken;
|
||||
private _token?: CancellationToken = undefined;
|
||||
private _parentListener?: IDisposable = undefined;
|
||||
|
||||
constructor(parent?: CancellationToken) {
|
||||
this._parentListener = parent && parent.onCancellationRequested(this.cancel, this);
|
||||
}
|
||||
|
||||
get token(): CancellationToken {
|
||||
if (!this._token) {
|
||||
@@ -112,6 +117,9 @@ export class CancellationTokenSource {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this._parentListener) {
|
||||
this._parentListener.dispose();
|
||||
}
|
||||
if (!this._token) {
|
||||
// ensure to initialize with an empty token if we had none
|
||||
this._token = CancellationToken.None;
|
||||
|
||||
@@ -130,7 +130,7 @@ export namespace Event {
|
||||
* @param leading Whether the event should fire in the leading phase of the timeout.
|
||||
* @param leakWarningThreshold The leak warning threshold override.
|
||||
*/
|
||||
export function debounce<T>(event: Event<T>, merge: (last: T, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<T>;
|
||||
export function debounce<T>(event: Event<T>, merge: (last: T | undefined, event: T) => T, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<T>;
|
||||
export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay?: number, leading?: boolean, leakWarningThreshold?: number): Event<O>;
|
||||
export function debounce<I, O>(event: Event<I>, merge: (last: O | undefined, event: I) => O, delay: number = 100, leading = false, leakWarningThreshold?: number): Event<O> {
|
||||
|
||||
@@ -488,7 +488,7 @@ export class Emitter<T> {
|
||||
private readonly _leakageMon?: LeakageMonitor;
|
||||
private _disposed: boolean = false;
|
||||
private _event?: Event<T>;
|
||||
private _deliveryQueue: [Listener<T>, T][];
|
||||
private _deliveryQueue?: LinkedList<[Listener<T>, T]>;
|
||||
protected _listeners?: LinkedList<Listener<T>>;
|
||||
|
||||
constructor(options?: EmitterOptions) {
|
||||
@@ -570,14 +570,14 @@ export class Emitter<T> {
|
||||
// the driver of this
|
||||
|
||||
if (!this._deliveryQueue) {
|
||||
this._deliveryQueue = [];
|
||||
this._deliveryQueue = new LinkedList();
|
||||
}
|
||||
|
||||
for (let iter = this._listeners.iterator(), e = iter.next(); !e.done; e = iter.next()) {
|
||||
this._deliveryQueue.push([e.value, event]);
|
||||
}
|
||||
|
||||
while (this._deliveryQueue.length > 0) {
|
||||
while (this._deliveryQueue.size > 0) {
|
||||
const [listener, event] = this._deliveryQueue.shift()!;
|
||||
try {
|
||||
if (typeof listener === 'function') {
|
||||
@@ -594,10 +594,10 @@ export class Emitter<T> {
|
||||
|
||||
dispose() {
|
||||
if (this._listeners) {
|
||||
this._listeners = undefined;
|
||||
this._listeners.clear();
|
||||
}
|
||||
if (this._deliveryQueue) {
|
||||
this._deliveryQueue.length = 0;
|
||||
this._deliveryQueue.clear();
|
||||
}
|
||||
if (this._leakageMon) {
|
||||
this._leakageMon.dispose();
|
||||
@@ -606,6 +606,51 @@ export class Emitter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export class PauseableEmitter<T> extends Emitter<T> {
|
||||
|
||||
private _isPaused = 0;
|
||||
private _eventQueue = new LinkedList<T>();
|
||||
private _mergeFn?: (input: T[]) => T;
|
||||
|
||||
constructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {
|
||||
super(options);
|
||||
this._mergeFn = options && options.merge;
|
||||
}
|
||||
|
||||
pause(): void {
|
||||
this._isPaused++;
|
||||
}
|
||||
|
||||
resume(): void {
|
||||
if (this._isPaused !== 0 && --this._isPaused === 0) {
|
||||
if (this._mergeFn) {
|
||||
// use the merge function to create a single composite
|
||||
// event. make a copy in case firing pauses this emitter
|
||||
const events = this._eventQueue.toArray();
|
||||
this._eventQueue.clear();
|
||||
super.fire(this._mergeFn(events));
|
||||
|
||||
} else {
|
||||
// no merging, fire each event individually and test
|
||||
// that this emitter isn't paused halfway through
|
||||
while (!this._isPaused && this._eventQueue.size !== 0) {
|
||||
super.fire(this._eventQueue.shift()!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fire(event: T): void {
|
||||
if (this._listeners) {
|
||||
if (this._isPaused !== 0) {
|
||||
this._eventQueue.push(event);
|
||||
} else {
|
||||
super.fire(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface IWaitUntil {
|
||||
waitUntil(thenable: Promise<any>): void;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { startsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings';
|
||||
import { startsWithIgnoreCase, equalsIgnoreCase, endsWith, rtrim } from 'vs/base/common/strings';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { sep, posix } from 'vs/base/common/path';
|
||||
import { sep, posix, isAbsolute, join, normalize } from 'vs/base/common/path';
|
||||
|
||||
function isPathSeparator(code: number) {
|
||||
return code === CharCode.Slash || code === CharCode.Backslash;
|
||||
@@ -227,4 +227,56 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo
|
||||
|
||||
export function isWindowsDriveLetter(char0: number): boolean {
|
||||
return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z;
|
||||
}
|
||||
|
||||
export function sanitizeFilePath(candidate: string, cwd: string): string {
|
||||
|
||||
// Special case: allow to open a drive letter without trailing backslash
|
||||
if (isWindows && endsWith(candidate, ':')) {
|
||||
candidate += sep;
|
||||
}
|
||||
|
||||
// Ensure absolute
|
||||
if (!isAbsolute(candidate)) {
|
||||
candidate = join(cwd, candidate);
|
||||
}
|
||||
|
||||
// Ensure normalized
|
||||
candidate = normalize(candidate);
|
||||
|
||||
// Ensure no trailing slash/backslash
|
||||
if (isWindows) {
|
||||
candidate = rtrim(candidate, sep);
|
||||
|
||||
// Special case: allow to open drive root ('C:\')
|
||||
if (endsWith(candidate, ':')) {
|
||||
candidate += sep;
|
||||
}
|
||||
|
||||
} else {
|
||||
candidate = rtrim(candidate, sep);
|
||||
|
||||
// Special case: allow to open root ('/')
|
||||
if (!candidate) {
|
||||
candidate = sep;
|
||||
}
|
||||
}
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
export function isRootOrDriveLetter(path: string): boolean {
|
||||
const pathNormalized = normalize(path);
|
||||
|
||||
if (isWindows) {
|
||||
if (path.length > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isWindowsDriveLetter(pathNormalized.charCodeAt(0))
|
||||
&& pathNormalized.charCodeAt(1) === CharCode.Colon
|
||||
&& (path.length === 2 || pathNormalized.charCodeAt(2) === CharCode.Backslash);
|
||||
}
|
||||
|
||||
return pathNormalized === posix.sep;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { CharCode } from 'vs/base/common/charCode';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export interface IExpression {
|
||||
[pattern: string]: boolean | SiblingClause | any;
|
||||
[pattern: string]: boolean | SiblingClause;
|
||||
}
|
||||
|
||||
export interface IRelativePattern {
|
||||
@@ -429,7 +429,7 @@ function toRegExp(pattern: string): ParsedStringPattern {
|
||||
*/
|
||||
export function match(pattern: string | IRelativePattern, path: string): boolean;
|
||||
export function match(expression: IExpression, path: string, hasSibling?: (name: string) => boolean): string /* the matching pattern */;
|
||||
export function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): any {
|
||||
export function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): boolean | string | null | Promise<string | null> {
|
||||
if (!arg1 || typeof path !== 'string') {
|
||||
return false;
|
||||
}
|
||||
@@ -447,14 +447,14 @@ export function match(arg1: string | IExpression | IRelativePattern, path: strin
|
||||
*/
|
||||
export function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern;
|
||||
export function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression;
|
||||
export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): any {
|
||||
export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): ParsedPattern | ParsedExpression {
|
||||
if (!arg1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Glob with String
|
||||
if (typeof arg1 === 'string' || isRelativePattern(arg1)) {
|
||||
const parsedPattern = parsePattern(arg1 as string | IRelativePattern, options);
|
||||
const parsedPattern = parsePattern(arg1, options);
|
||||
if (parsedPattern === NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -512,23 +512,12 @@ function listToMap(list: string[]) {
|
||||
return map;
|
||||
}
|
||||
|
||||
export function isRelativePattern(obj: any): obj is IRelativePattern {
|
||||
export function isRelativePattern(obj: unknown): obj is IRelativePattern {
|
||||
const rp = obj as IRelativePattern;
|
||||
|
||||
return rp && typeof rp.base === 'string' && typeof rp.pattern === 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `parse`, but the ParsedExpression is guaranteed to return a Promise
|
||||
*/
|
||||
export function parseToAsync(expression: IExpression, options?: IGlobOptions): ParsedExpression {
|
||||
const parsedExpression = parse(expression, options);
|
||||
return (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise<boolean>): string | null | Promise<string | null> => {
|
||||
const result = parsedExpression(path, basename, hasSibling);
|
||||
return isThenable(result) ? result : Promise.resolve(result);
|
||||
};
|
||||
}
|
||||
|
||||
export function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] {
|
||||
return (<ParsedStringPattern>patternOrExpression).allBasenames || [];
|
||||
}
|
||||
@@ -613,7 +602,7 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse
|
||||
return resultExpression;
|
||||
}
|
||||
|
||||
function parseExpressionPattern(pattern: string, value: any, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) {
|
||||
function parseExpressionPattern(pattern: string, value: boolean | SiblingClause, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) {
|
||||
if (value === false) {
|
||||
return NULL; // pattern is disabled
|
||||
}
|
||||
|
||||
@@ -6,19 +6,24 @@
|
||||
import { Iterator, IteratorResult, FIN } from 'vs/base/common/iterator';
|
||||
|
||||
class Node<E> {
|
||||
|
||||
static readonly Undefined = new Node<any>(undefined);
|
||||
|
||||
element: E;
|
||||
next: Node<E> | undefined;
|
||||
prev: Node<E> | undefined;
|
||||
next: Node<E>;
|
||||
prev: Node<E>;
|
||||
|
||||
constructor(element: E) {
|
||||
this.element = element;
|
||||
this.next = Node.Undefined;
|
||||
this.prev = Node.Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class LinkedList<E> {
|
||||
|
||||
private _first: Node<E> | undefined;
|
||||
private _last: Node<E> | undefined;
|
||||
private _first: Node<E> = Node.Undefined;
|
||||
private _last: Node<E> = Node.Undefined;
|
||||
private _size: number = 0;
|
||||
|
||||
get size(): number {
|
||||
@@ -26,12 +31,12 @@ export class LinkedList<E> {
|
||||
}
|
||||
|
||||
isEmpty(): boolean {
|
||||
return !this._first;
|
||||
return this._first === Node.Undefined;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
this._first = Node.Undefined;
|
||||
this._last = Node.Undefined;
|
||||
this._size = 0;
|
||||
}
|
||||
|
||||
@@ -45,7 +50,7 @@ export class LinkedList<E> {
|
||||
|
||||
private _insert(element: E, atTheEnd: boolean): () => void {
|
||||
const newNode = new Node(element);
|
||||
if (!this._first) {
|
||||
if (this._first === Node.Undefined) {
|
||||
this._first = newNode;
|
||||
this._last = newNode;
|
||||
|
||||
@@ -64,12 +69,18 @@ export class LinkedList<E> {
|
||||
oldFirst.prev = newNode;
|
||||
}
|
||||
this._size += 1;
|
||||
return this._remove.bind(this, newNode);
|
||||
|
||||
let didRemove = false;
|
||||
return () => {
|
||||
if (!didRemove) {
|
||||
didRemove = true;
|
||||
this._remove(newNode);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
shift(): E | undefined {
|
||||
if (!this._first) {
|
||||
if (this._first === Node.Undefined) {
|
||||
return undefined;
|
||||
} else {
|
||||
const res = this._first.element;
|
||||
@@ -79,7 +90,7 @@ export class LinkedList<E> {
|
||||
}
|
||||
|
||||
pop(): E | undefined {
|
||||
if (!this._last) {
|
||||
if (this._last === Node.Undefined) {
|
||||
return undefined;
|
||||
} else {
|
||||
const res = this._last.element;
|
||||
@@ -89,38 +100,30 @@ export class LinkedList<E> {
|
||||
}
|
||||
|
||||
private _remove(node: Node<E>): void {
|
||||
let candidate: Node<E> | undefined = this._first;
|
||||
while (candidate instanceof Node) {
|
||||
if (candidate !== node) {
|
||||
candidate = candidate.next;
|
||||
continue;
|
||||
}
|
||||
if (candidate.prev && candidate.next) {
|
||||
// middle
|
||||
const anchor = candidate.prev;
|
||||
anchor.next = candidate.next;
|
||||
candidate.next.prev = anchor;
|
||||
if (node.prev !== Node.Undefined && node.next !== Node.Undefined) {
|
||||
// middle
|
||||
const anchor = node.prev;
|
||||
anchor.next = node.next;
|
||||
node.next.prev = anchor;
|
||||
|
||||
} else if (!candidate.prev && !candidate.next) {
|
||||
// only node
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
} else if (node.prev === Node.Undefined && node.next === Node.Undefined) {
|
||||
// only node
|
||||
this._first = Node.Undefined;
|
||||
this._last = Node.Undefined;
|
||||
|
||||
} else if (!candidate.next) {
|
||||
// last
|
||||
this._last = this._last!.prev!;
|
||||
this._last.next = undefined;
|
||||
} else if (node.next === Node.Undefined) {
|
||||
// last
|
||||
this._last = this._last!.prev!;
|
||||
this._last.next = Node.Undefined;
|
||||
|
||||
} else if (!candidate.prev) {
|
||||
// first
|
||||
this._first = this._first!.next!;
|
||||
this._first.prev = undefined;
|
||||
}
|
||||
|
||||
// done
|
||||
this._size -= 1;
|
||||
break;
|
||||
} else if (node.prev === Node.Undefined) {
|
||||
// first
|
||||
this._first = this._first!.next!;
|
||||
this._first.prev = Node.Undefined;
|
||||
}
|
||||
|
||||
// done
|
||||
this._size -= 1;
|
||||
}
|
||||
|
||||
iterator(): Iterator<E> {
|
||||
@@ -128,7 +131,7 @@ export class LinkedList<E> {
|
||||
let node = this._first;
|
||||
return {
|
||||
next(): IteratorResult<E> {
|
||||
if (!node) {
|
||||
if (node === Node.Undefined) {
|
||||
return FIN;
|
||||
}
|
||||
|
||||
@@ -145,7 +148,7 @@ export class LinkedList<E> {
|
||||
|
||||
toArray(): E[] {
|
||||
const result: E[] = [];
|
||||
for (let node = this._first; node instanceof Node; node = node.next) {
|
||||
for (let node = this._first; node !== Node.Undefined; node = node.next) {
|
||||
result.push(node.element);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -175,34 +175,6 @@ export function equals(one: any, other: any): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
function arrayToHash(array: string[]): { [name: string]: true } {
|
||||
const result: any = {};
|
||||
for (const e of array) {
|
||||
result[e] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of strings, returns a function which, given a string
|
||||
* returns true or false whether the string is in that array.
|
||||
*/
|
||||
export function createKeywordMatcher(arr: string[], caseInsensitive: boolean = false): (str: string) => boolean {
|
||||
if (caseInsensitive) {
|
||||
arr = arr.map(function (x) { return x.toLowerCase(); });
|
||||
}
|
||||
const hash = arrayToHash(arr);
|
||||
if (caseInsensitive) {
|
||||
return function (word) {
|
||||
return hash[word.toLowerCase()] !== undefined && hash.hasOwnProperty(word.toLowerCase());
|
||||
};
|
||||
} else {
|
||||
return function (word) {
|
||||
return hash[word] !== undefined && hash.hasOwnProperty(word);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls JSON.Stringify with a replacer to break apart any circular references.
|
||||
* This prevents JSON.stringify from throwing the exception
|
||||
|
||||
@@ -87,6 +87,17 @@ export const enum TerminateResponseCode {
|
||||
ProcessNotFound = 3,
|
||||
}
|
||||
|
||||
export interface ProcessItem {
|
||||
name: string;
|
||||
cmd: string;
|
||||
pid: number;
|
||||
ppid: number;
|
||||
load: number;
|
||||
mem: number;
|
||||
|
||||
children?: ProcessItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a VS Code process environment by removing all Electron/VS Code-related values.
|
||||
*/
|
||||
|
||||
@@ -159,27 +159,6 @@ export function validateConstraint(arg: any, constraint: TypeConstraint | undefi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object of the provided class and will call the constructor with
|
||||
* any additional argument supplied.
|
||||
*/
|
||||
export function create(ctor: Function, ...args: any[]): any {
|
||||
if (isNativeClass(ctor)) {
|
||||
return new (ctor as any)(...args);
|
||||
} else {
|
||||
const obj = Object.create(ctor.prototype);
|
||||
ctor.apply(obj, args);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/32235645/1499159
|
||||
function isNativeClass(thing: any): boolean {
|
||||
return typeof thing === 'function'
|
||||
&& thing.hasOwnProperty('prototype')
|
||||
&& !thing.hasOwnProperty('arguments');
|
||||
}
|
||||
|
||||
export function getAllPropertyNames(obj: object): string[] {
|
||||
let res: string[] = [];
|
||||
let proto = Object.getPrototypeOf(obj);
|
||||
@@ -202,4 +181,4 @@ export function withNullAsUndefined<T>(x: T | null): T | undefined {
|
||||
*/
|
||||
export function withUndefinedAsNull<T>(x: T | undefined): T | null {
|
||||
return typeof x === 'undefined' ? null : x;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function toUint8ArrayBuffer(str: string): ArrayBuffer {
|
||||
|
||||
if (typeof TextEncoder !== 'undefined') {
|
||||
return new TextEncoder().encode(str).buffer;
|
||||
}
|
||||
|
||||
let i: number, len: number, length = 0, charCode = 0, trailCharCode = 0, codepoint = 0;
|
||||
|
||||
// First pass, for the size
|
||||
for (i = 0, len = str.length; i < len; i++) {
|
||||
charCode = str.charCodeAt(i);
|
||||
|
||||
// Surrogate pair
|
||||
if (charCode >= 0xD800 && charCode < 0xDC00) {
|
||||
trailCharCode = str.charCodeAt(++i);
|
||||
|
||||
if (!(trailCharCode >= 0xDC00 && trailCharCode < 0xE000)) {
|
||||
throw new Error('Invalid char code');
|
||||
}
|
||||
|
||||
// Code point can be obtained by subtracting 0xD800 and 0xDC00 from both char codes respectively
|
||||
// and joining the 10 least significant bits from each, finally adding 0x10000.
|
||||
codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000;
|
||||
|
||||
} else {
|
||||
codepoint = charCode;
|
||||
}
|
||||
|
||||
length += byteSizeInUTF8(codepoint);
|
||||
}
|
||||
|
||||
let result = new ArrayBuffer(length);
|
||||
let view = new Uint8Array(result);
|
||||
let pos = 0;
|
||||
|
||||
// Second pass, for the data
|
||||
for (i = 0, len = str.length; i < len; i++) {
|
||||
charCode = str.charCodeAt(i);
|
||||
|
||||
if (charCode >= 0xD800 && charCode < 0xDC00) {
|
||||
trailCharCode = str.charCodeAt(++i);
|
||||
codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000;
|
||||
} else {
|
||||
codepoint = charCode;
|
||||
}
|
||||
|
||||
pos += writeUTF8(codepoint, view, pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function byteSizeInUTF8(codePoint: number): number {
|
||||
codePoint = codePoint >>> 0;
|
||||
|
||||
if (codePoint < 0x80) {
|
||||
return 1;
|
||||
} else if (codePoint < 0x800) {
|
||||
return 2;
|
||||
} else if (codePoint < 0x10000) {
|
||||
return 3;
|
||||
} else if (codePoint < 0x200000) {
|
||||
return 4;
|
||||
} else if (codePoint < 0x4000000) {
|
||||
return 5;
|
||||
} else if (codePoint < 0x80000000) {
|
||||
return 6;
|
||||
} else {
|
||||
throw new Error('Code point 0x' + toHexString(codePoint) + ' not encodable in UTF8.');
|
||||
}
|
||||
}
|
||||
|
||||
function writeUTF8(codePoint: number, buffer: Uint8Array, pos: number): number {
|
||||
|
||||
// How many bits needed for codePoint
|
||||
let byteSize = byteSizeInUTF8(codePoint);
|
||||
|
||||
// 0xxxxxxx
|
||||
if (byteSize === 1) {
|
||||
buffer[pos] = codePoint;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 110xxxxx 10xxxxxx
|
||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
// 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
// 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
// first byte
|
||||
buffer[pos] = ((0xFC << (6 - byteSize)) | (codePoint >>> (6 * (byteSize - 1)))) & 0xFF;
|
||||
|
||||
// successive bytes
|
||||
for (let i = 1; i < byteSize; i++) {
|
||||
buffer[pos + i] = (0x80 | (0x3F & (codePoint >>> (6 * (byteSize - i - 1))))) & 0xFF;
|
||||
}
|
||||
|
||||
return byteSize;
|
||||
}
|
||||
|
||||
function leftPad(value: string, length: number, char: string = '0'): string {
|
||||
return new Array(length - value.length + 1).join(char) + value;
|
||||
}
|
||||
|
||||
function toHexString(value: number, bitsize: number = 32): string {
|
||||
return leftPad((value >>> 0).toString(16), bitsize / 4);
|
||||
}
|
||||
Reference in New Issue
Block a user