@idlebox/common 1.3.15 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{dist → lib}/common-alpha.d.ts +10 -0
- package/{dist → lib}/common-beta.d.ts +10 -0
- package/{dist → lib}/common-public.d.ts +10 -0
- package/{dist → lib}/common.d.ts +10 -0
- package/lib/function/callbackList.cjs +4 -0
- package/lib/function/callbackList.cjs.map +1 -1
- package/lib/function/callbackList.js +4 -0
- package/lib/function/callbackList.js.map +1 -1
- package/lib/string/concatType.generated.cjs +8 -0
- package/lib/string/concatType.generated.cjs.map +1 -1
- package/lib/string/concatType.generated.js +8 -0
- package/lib/string/concatType.generated.js.map +1 -1
- package/{dist → lib}/tsdoc-metadata.json +1 -1
- package/package.json +12 -12
- package/src/array/arrayDiff.ts +31 -0
- package/src/array/arraySame.ts +15 -0
- package/src/array/arrayUnique.ts +50 -0
- package/src/array/normalizeArray.ts +13 -0
- package/src/array/sortAlpha.ts +15 -0
- package/src/date/consts.ts +5 -0
- package/src/date/isInvalid.ts +6 -0
- package/src/date/sibling.ts +28 -0
- package/src/date/timeString.ts +150 -0
- package/src/date/unix.ts +13 -0
- package/src/debugging/serializable.ts +146 -0
- package/src/debugging/tryInspect.ts +37 -0
- package/src/error/convertUnknown.ts +10 -0
- package/src/error/getFrame.ts +13 -0
- package/src/function/asyncCallbackList.ts +75 -0
- package/src/function/callbackList.ts +88 -0
- package/src/function/delayCallbackList.ts +45 -0
- package/src/function/functionName.ts +39 -0
- package/src/index.generated.ts +289 -0
- package/src/lifecycle/dispose/bridges/rxjs.ts +6 -0
- package/src/lifecycle/dispose/disposableEvent.ts +117 -0
- package/src/lifecycle/dispose/disposedError.ts +16 -0
- package/src/lifecycle/dispose/lifecycle.async.ts +61 -0
- package/src/lifecycle/dispose/lifecycle.global.ts +61 -0
- package/src/lifecycle/dispose/lifecycle.sync.ts +79 -0
- package/src/lifecycle/dispose/lifecycle.ts +28 -0
- package/src/lifecycle/event/event.ts +81 -0
- package/src/lifecycle/event/memorized.ts +39 -0
- package/src/lifecycle/promise/cancel.ts +16 -0
- package/src/lifecycle/promise/cancellationToken/driver.browser.ts +55 -0
- package/src/lifecycle/promise/cancellationToken/driver.common.ts +43 -0
- package/src/lifecycle/promise/cancellationToken/source.ts +48 -0
- package/src/lifecycle/promise/deferredPromise.ts +104 -0
- package/src/lifecycle/timeout/timeout.ts +48 -0
- package/src/lifecycle/timeout/timeoutError.ts +16 -0
- package/src/log/logger.ts +148 -0
- package/src/mapSet/customSet.ts +91 -0
- package/src/mapSet/extendMap.ts +40 -0
- package/src/misc/assertNotNull.ts +21 -0
- package/src/object/definePublicConstant.ts +10 -0
- package/src/object/initOnRead.ts +27 -0
- package/src/object/objectPath.ts +10 -0
- package/src/object/objectSame.ts +52 -0
- package/src/path/isAbsolute.ts +11 -0
- package/src/path/normalizePath.ts +8 -0
- package/src/path/pathArray.ts +42 -0
- package/src/platform/globalObject.ts +22 -0
- package/src/platform/globalSingleton.ts +82 -0
- package/src/platform/globalSymbol.ts +36 -0
- package/src/platform/os.ts +46 -0
- package/src/promise/awaitIterator.ts +19 -0
- package/src/promise/finishAllPromise.ts +50 -0
- package/src/promise/promiseBool.ts +10 -0
- package/src/promise/promisePool.ts +40 -0
- package/src/promise/timeoutPromisePool.ts +22 -0
- package/src/reflection/classes/hookClass.ts +47 -0
- package/src/reflection/classes/singleton.ts +33 -0
- package/src/reflection/methods/bind.ts +30 -0
- package/src/reflection/methods/initOnRead.ts +11 -0
- package/src/reflection/methods/memorize.ts +33 -0
- package/src/string/castCase.ts +44 -0
- package/src/string/concatType.generated.ts +265 -0
- package/src/string/concatType.generator.ts +31 -0
- package/src/string/escapeRegexp.ts +4 -0
- package/src/string/pad2.ts +11 -0
- package/src/string/sizeString.ts +52 -0
- package/src/tsconfig.json +14 -0
- package/src/typingHelper/deep.partial.ts +16 -0
- package/src/typingHelper/deep.readonly.ts +16 -0
- package/src/typingHelper/deep.required.ts +16 -0
- package/src/typingHelper/deep.writable.ts +16 -0
- package/src/typingHelper/literal.ts +1 -0
- package/docs/common.api.json +0 -21737
- package/docs/common.api.md +0 -1139
- package/docs/package-public.d.ts +0 -952
- package/docs/tsdoc-metadata.json +0 -11
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IDisposable } from '../dispose/lifecycle';
|
|
2
|
+
|
|
3
|
+
export interface EventHandler<T> {
|
|
4
|
+
(data: T): void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface EventRegister<T> {
|
|
8
|
+
(callback: EventHandler<T>): IDisposable;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 事件注册对象
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export class Emitter<T> implements IDisposable {
|
|
16
|
+
private readonly _callbacks: EventHandler<T>[] = [];
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
this.handle = this.handle.bind(this);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @returns 当前注册回调数量
|
|
24
|
+
*/
|
|
25
|
+
public listenerCount() {
|
|
26
|
+
return this._callbacks.length;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 触发本事件
|
|
31
|
+
* @param data 回调数据
|
|
32
|
+
*/
|
|
33
|
+
public fire(data: T) {
|
|
34
|
+
for (const callback of this._callbacks) {
|
|
35
|
+
callback(data);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 与 `fire()`相同,但是忽略任何错误,并且即便出错也继续执行全部callback
|
|
41
|
+
*/
|
|
42
|
+
public fireNoError(data: T) {
|
|
43
|
+
for (const callback of this._callbacks) {
|
|
44
|
+
try {
|
|
45
|
+
callback(data);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
console.error('Error ignored: ', e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 获取handle()方法的引用
|
|
54
|
+
*/
|
|
55
|
+
get register(): EventRegister<T> {
|
|
56
|
+
return this.handle;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 注册本事件的新回调
|
|
61
|
+
* @param callback 回调函数
|
|
62
|
+
*/
|
|
63
|
+
handle(callback: EventHandler<T>): IDisposable {
|
|
64
|
+
this._callbacks.unshift(callback);
|
|
65
|
+
return {
|
|
66
|
+
dispose: () => {
|
|
67
|
+
const index = this._callbacks.indexOf(callback);
|
|
68
|
+
if (index !== -1) {
|
|
69
|
+
this._callbacks.splice(index, 1);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
dispose() {
|
|
76
|
+
this._callbacks.length = 0;
|
|
77
|
+
this.fire = this.handle = () => {
|
|
78
|
+
throw new Error('Event is disposed');
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { IDisposable } from '../dispose/lifecycle';
|
|
2
|
+
import { Emitter, EventHandler } from './event';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 会记住上次fire的内容,并在每个新的handler注册时立即调用一次的Emitter
|
|
6
|
+
* 显然,这会对fire的内容保留一个引用,可以调用forget()取消
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export class MemorizedEmitter<T> extends Emitter<T> {
|
|
10
|
+
private _memo?: T;
|
|
11
|
+
private _is_memo: boolean = false;
|
|
12
|
+
|
|
13
|
+
public override fire(data: T) {
|
|
14
|
+
this._memo = data;
|
|
15
|
+
this._is_memo = true;
|
|
16
|
+
return super.fire(data);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public override fireNoError(data: T) {
|
|
20
|
+
this._memo = data;
|
|
21
|
+
this._is_memo = true;
|
|
22
|
+
return super.fireNoError(data);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public override handle(callback: EventHandler<T>): IDisposable {
|
|
26
|
+
if (this._is_memo) callback(this._memo!);
|
|
27
|
+
return super.handle(callback);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public forget() {
|
|
31
|
+
delete this._memo;
|
|
32
|
+
this._is_memo = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
dispose(): void {
|
|
36
|
+
this.forget();
|
|
37
|
+
super.dispose();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const canceledName = 'Canceled';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error when cancel() is called
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export class CanceledError extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(canceledName);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** @public */
|
|
14
|
+
export function isCanceledError(error: any): boolean {
|
|
15
|
+
return error instanceof CanceledError;
|
|
16
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EventHandler } from '../../event/event';
|
|
2
|
+
|
|
3
|
+
import type { CancellationDriver, __CancellationToken } from './source';
|
|
4
|
+
|
|
5
|
+
declare const AbortController: any; // TODO
|
|
6
|
+
declare type AbortController = any; // TODO
|
|
7
|
+
|
|
8
|
+
/** @internal */
|
|
9
|
+
export class CancellationDriverBrowser implements CancellationDriver {
|
|
10
|
+
private readonly controller: AbortController;
|
|
11
|
+
public readonly token: __CancellationToken;
|
|
12
|
+
private readonly disposeList: (() => void)[] = [];
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
this.controller = new AbortController();
|
|
16
|
+
|
|
17
|
+
const signal = this.controller.signal;
|
|
18
|
+
signal.addEventListener('abort', () => {
|
|
19
|
+
token.isCancellationRequested = true;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const disposeList = this.disposeList;
|
|
23
|
+
const token = {
|
|
24
|
+
isCancellationRequested: false,
|
|
25
|
+
onCancellationRequested(listener: EventHandler<void>) {
|
|
26
|
+
const callback = () => listener();
|
|
27
|
+
|
|
28
|
+
signal.addEventListener('abort', callback);
|
|
29
|
+
|
|
30
|
+
const dispose = () => signal.removeEventListener('abort', callback);
|
|
31
|
+
disposeList.push(dispose);
|
|
32
|
+
|
|
33
|
+
return { dispose };
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
this.token = token;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
cancel() {
|
|
41
|
+
if (this.token.isCancellationRequested) {
|
|
42
|
+
console.warn('[CancellationTokenSource] is already canceled.');
|
|
43
|
+
} else {
|
|
44
|
+
this.token.isCancellationRequested = true;
|
|
45
|
+
this.controller.abort();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
dispose() {
|
|
50
|
+
for (const removeListener of this.disposeList) removeListener();
|
|
51
|
+
if (!this.token.isCancellationRequested) {
|
|
52
|
+
this.controller.abort();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { IDisposable } from '../../dispose/lifecycle';
|
|
2
|
+
import { Emitter, EventHandler } from '../../event/event';
|
|
3
|
+
|
|
4
|
+
import type { CancellationDriver, __CancellationToken } from './source';
|
|
5
|
+
|
|
6
|
+
/** @internal */
|
|
7
|
+
export class CancellationDriverCommon implements CancellationDriver {
|
|
8
|
+
private readonly emitter: Emitter<void>;
|
|
9
|
+
public readonly token: __CancellationToken;
|
|
10
|
+
private readonly disposeList: IDisposable[] = [];
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
const emitter = new Emitter<void>();
|
|
14
|
+
this.emitter = emitter;
|
|
15
|
+
|
|
16
|
+
const disposeList = this.disposeList;
|
|
17
|
+
const token = {
|
|
18
|
+
isCancellationRequested: false,
|
|
19
|
+
onCancellationRequested(callback: EventHandler<void>) {
|
|
20
|
+
const ret = emitter.handle(callback);
|
|
21
|
+
disposeList.push(ret);
|
|
22
|
+
return ret;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
this.token = token;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cancel() {
|
|
29
|
+
if (this.token.isCancellationRequested) {
|
|
30
|
+
console.warn('[CancellationTokenSource] is already canceled.');
|
|
31
|
+
} else {
|
|
32
|
+
this.token.isCancellationRequested = true;
|
|
33
|
+
this.emitter.fire();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
dispose() {
|
|
38
|
+
for (const listen of this.disposeList) listen.dispose();
|
|
39
|
+
if (!this.token.isCancellationRequested) {
|
|
40
|
+
this.cancel();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { globalObject } from '../../../platform/globalObject';
|
|
2
|
+
import { IDisposable } from '../../dispose/lifecycle';
|
|
3
|
+
import { DisposableOnce } from '../../dispose/lifecycle.sync';
|
|
4
|
+
import { EventHandler } from '../../event/event';
|
|
5
|
+
import { CancellationDriverBrowser } from './driver.browser';
|
|
6
|
+
import { CancellationDriverCommon } from './driver.common';
|
|
7
|
+
|
|
8
|
+
/** @public */
|
|
9
|
+
export interface CancellationToken {
|
|
10
|
+
readonly isCancellationRequested: boolean;
|
|
11
|
+
onCancellationRequested(callback: EventHandler<void>): IDisposable;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** @internal */
|
|
15
|
+
export interface __CancellationToken {
|
|
16
|
+
isCancellationRequested: boolean;
|
|
17
|
+
onCancellationRequested(callback: EventHandler<void>): IDisposable;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
export interface CancellationDriver extends IDisposable {
|
|
22
|
+
readonly token: CancellationToken;
|
|
23
|
+
cancel(): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** @public */
|
|
27
|
+
export class CancellationTokenSource extends DisposableOnce implements IDisposable {
|
|
28
|
+
private readonly driver: CancellationDriver;
|
|
29
|
+
public readonly token: CancellationToken;
|
|
30
|
+
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
if ('AbortController' in globalObject) {
|
|
34
|
+
this.driver = new CancellationDriverBrowser();
|
|
35
|
+
} else {
|
|
36
|
+
this.driver = new CancellationDriverCommon();
|
|
37
|
+
}
|
|
38
|
+
this.token = this.driver.token;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
cancel(): void {
|
|
42
|
+
this.driver.cancel();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_dispose(): void {
|
|
46
|
+
this.driver.dispose();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { CanceledError } from './cancel';
|
|
2
|
+
|
|
3
|
+
export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
|
|
4
|
+
export type ProgressCallback<T = any> = (value: T) => void;
|
|
5
|
+
|
|
6
|
+
export interface IProgressHolder<T, PT> {
|
|
7
|
+
progress(fn: ProgressCallback<PT>): Promise<T> & IProgressHolder<T, PT>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* a promise can resolve or reject later
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export class DeferredPromise<T, PT = any> {
|
|
15
|
+
public readonly p: Promise<T> & IProgressHolder<T, PT>;
|
|
16
|
+
private declare _completeCallback: ValueCallback<T>;
|
|
17
|
+
private declare _errorCallback: (err: any) => void;
|
|
18
|
+
private _state: boolean | null = null;
|
|
19
|
+
private _progressList?: ProgressCallback<PT>[] = [];
|
|
20
|
+
|
|
21
|
+
constructor() {
|
|
22
|
+
this.p = Object.assign(
|
|
23
|
+
new Promise<any>((c, e) => {
|
|
24
|
+
this._completeCallback = c;
|
|
25
|
+
this._errorCallback = e;
|
|
26
|
+
}),
|
|
27
|
+
{
|
|
28
|
+
progress: (fn: ProgressCallback<PT>) => {
|
|
29
|
+
this.progress(fn);
|
|
30
|
+
return this.p;
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
this.p
|
|
35
|
+
.finally(() => {
|
|
36
|
+
delete this._progressList;
|
|
37
|
+
})
|
|
38
|
+
.catch(() => void 0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
notify(progress: PT): this {
|
|
42
|
+
for (const cb of this._progressList!) {
|
|
43
|
+
cb(progress);
|
|
44
|
+
}
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
progress(fn: ProgressCallback<PT>): void {
|
|
49
|
+
this._progressList!.push(fn);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get completed(): boolean {
|
|
53
|
+
return typeof this._state === 'boolean';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get resolved(): boolean {
|
|
57
|
+
return this._state === true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get rejected(): boolean {
|
|
61
|
+
return this._state === false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* resolve the promise
|
|
66
|
+
*/
|
|
67
|
+
public complete(value: T) {
|
|
68
|
+
this._state = true;
|
|
69
|
+
this._completeCallback(value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* reject the promise
|
|
74
|
+
*/
|
|
75
|
+
public error(err: any) {
|
|
76
|
+
this._state = false;
|
|
77
|
+
this._errorCallback(err);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* reject the promise with CancelError
|
|
82
|
+
*/
|
|
83
|
+
public cancel() {
|
|
84
|
+
this._state = false;
|
|
85
|
+
this._errorCallback(new CanceledError());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Convert promise into deferred
|
|
90
|
+
* returns a DeferredPromise, resolve when prev resolve, reject when prev reject
|
|
91
|
+
*/
|
|
92
|
+
static wrap(prev: Promise<any>) {
|
|
93
|
+
const p = new DeferredPromise();
|
|
94
|
+
prev.then(
|
|
95
|
+
(d) => {
|
|
96
|
+
p.complete(d);
|
|
97
|
+
},
|
|
98
|
+
(e) => {
|
|
99
|
+
p.error(e);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
return p;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { TimeoutError } from './timeoutError';
|
|
2
|
+
import { DeferredPromise } from '../promise/deferredPromise';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @returns promise reject with TimeoutError after specific time
|
|
6
|
+
*/
|
|
7
|
+
export function timeout(ms: number, error = 'no response'): Promise<never> {
|
|
8
|
+
return new Promise((_, reject) => {
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
reject(new TimeoutError(ms, error));
|
|
11
|
+
}, ms);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @returns promise resolve after specific time
|
|
17
|
+
*/
|
|
18
|
+
export function sleep(ms: number): Promise<void> {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
resolve();
|
|
22
|
+
}, ms);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function timeoutPromise<T>(ms: number, p: Promise<T>): Promise<T>;
|
|
27
|
+
export function timeoutPromise<T>(ms: number, message: string, p: Promise<T>): Promise<T>;
|
|
28
|
+
export function timeoutPromise<T, PT = any>(ms: number, p: DeferredPromise<T, PT>): DeferredPromise<T, PT>;
|
|
29
|
+
export function timeoutPromise<T, PT = any>(
|
|
30
|
+
ms: number,
|
|
31
|
+
message: string,
|
|
32
|
+
p: DeferredPromise<T, PT>
|
|
33
|
+
): DeferredPromise<T, PT>;
|
|
34
|
+
|
|
35
|
+
export function timeoutPromise<T>(ms: number, message: string | T, p?: T): T {
|
|
36
|
+
let msg: string | undefined;
|
|
37
|
+
if (typeof message !== 'string') {
|
|
38
|
+
p = message;
|
|
39
|
+
msg = undefined;
|
|
40
|
+
} else {
|
|
41
|
+
msg = message;
|
|
42
|
+
}
|
|
43
|
+
if (p instanceof DeferredPromise) {
|
|
44
|
+
return Promise.race([p.p, timeout(ms, msg)]).then(() => p) as any;
|
|
45
|
+
} else {
|
|
46
|
+
return Promise.race([p, timeout(ms, msg)]).then(() => p) as any;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { humanDate } from '../../date/timeString';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error when timeout() done
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export class TimeoutError extends Error {
|
|
8
|
+
constructor(time: number, what: string = 'no response') {
|
|
9
|
+
super(`Timeout: ${what} in ${humanDate.deltaTiny(time)}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** @public */
|
|
14
|
+
export function isTimeoutError(error: Error): error is TimeoutError {
|
|
15
|
+
return error instanceof TimeoutError;
|
|
16
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { nameFunction } from '../function/functionName';
|
|
2
|
+
import { isWeb } from '../platform/os';
|
|
3
|
+
|
|
4
|
+
export enum ColorKind {
|
|
5
|
+
DISABLE,
|
|
6
|
+
TERMINAL,
|
|
7
|
+
WEB,
|
|
8
|
+
DETECT,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface WrappedConsoleOptions {
|
|
12
|
+
parent?: Console;
|
|
13
|
+
bind?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export abstract class WrappedConsole {
|
|
17
|
+
public declare info: Console['info'];
|
|
18
|
+
public declare log: Console['log'];
|
|
19
|
+
public declare success: Console['log'];
|
|
20
|
+
public declare debug: Console['debug'];
|
|
21
|
+
public declare error: Console['error'];
|
|
22
|
+
public declare trace: Console['trace'];
|
|
23
|
+
public declare warn: Console['warn'];
|
|
24
|
+
public declare assert: Console['assert'];
|
|
25
|
+
|
|
26
|
+
public declare time: Console['time'];
|
|
27
|
+
public declare timeEnd: Console['timeEnd'];
|
|
28
|
+
public declare timeLog: Console['timeLog'];
|
|
29
|
+
public declare count: Console['count'];
|
|
30
|
+
public declare countReset: Console['countReset'];
|
|
31
|
+
public declare group: Console['group'];
|
|
32
|
+
public declare groupCollapsed: Console['groupCollapsed'];
|
|
33
|
+
public declare groupEnd: Console['groupEnd'];
|
|
34
|
+
|
|
35
|
+
public declare table: Console['table'];
|
|
36
|
+
public declare dir: Console['dir'];
|
|
37
|
+
public declare clear: Console['clear'];
|
|
38
|
+
|
|
39
|
+
protected readonly title: string;
|
|
40
|
+
protected readonly parent: Console;
|
|
41
|
+
protected readonly bind: boolean;
|
|
42
|
+
|
|
43
|
+
constructor(title: string, { parent, bind }: WrappedConsoleOptions = {}) {
|
|
44
|
+
this.title = title;
|
|
45
|
+
this.parent = parent || console;
|
|
46
|
+
this.bind = bind || false;
|
|
47
|
+
|
|
48
|
+
this.info = this.wrapMessageAt('info', 0);
|
|
49
|
+
this.log = this.wrapMessageAt('log', 0);
|
|
50
|
+
this.success = this.wrapMessageAt('log', 0);
|
|
51
|
+
this.debug = this.wrapMessageAt('debug', 0);
|
|
52
|
+
this.error = this.wrapMessageAt('error', 0);
|
|
53
|
+
this.trace = this.wrapMessageAt('trace', 0);
|
|
54
|
+
this.warn = this.wrapMessageAt('warn', 0);
|
|
55
|
+
this.assert = this.wrapMessageAt('assert', 1);
|
|
56
|
+
|
|
57
|
+
this.time = this.wrapMessageAt('time', 0);
|
|
58
|
+
this.timeEnd = this.wrapMessageAt('timeEnd', 0);
|
|
59
|
+
this.timeLog = this.wrapMessageAt('timeLog', 0);
|
|
60
|
+
this.count = this.wrapMessageAt('count', 0);
|
|
61
|
+
this.countReset = this.wrapMessageAt('countReset', 0);
|
|
62
|
+
this.group = this.wrapMessageAt('group', 0);
|
|
63
|
+
this.groupCollapsed = this.wrapMessageAt('groupCollapsed', 0);
|
|
64
|
+
|
|
65
|
+
this.groupEnd = this.wrapSimple('groupEnd');
|
|
66
|
+
this.table = this.wrapExtra('table', ' <<table>>');
|
|
67
|
+
this.dir = this.wrapExtra('dir', ' <<dir>>');
|
|
68
|
+
this.clear = this.wrapExtra('clear', ' <<clear>>');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected wrap<T extends keyof Omit<Console & { Console: any }, 'Console'>>(original: T): Function {
|
|
72
|
+
if (this.bind) {
|
|
73
|
+
return this.parent[original].bind(this.parent) as any;
|
|
74
|
+
} else {
|
|
75
|
+
return this.parent[original];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private wrapSimple<T extends keyof Omit<Console & { Console: any }, 'Console'>>(original: T): Console[T] {
|
|
80
|
+
return nameFunction('console:' + original, this.wrap(original) as any);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private wrapExtra<T extends keyof Omit<Console & { Console: any }, 'Console'>>(
|
|
84
|
+
original: T,
|
|
85
|
+
exMessage: string
|
|
86
|
+
): Console[T] {
|
|
87
|
+
const bindedFn = this.wrap(original);
|
|
88
|
+
return nameFunction('console:' + original, (...args: any[]) => {
|
|
89
|
+
this.log(exMessage);
|
|
90
|
+
bindedFn(...args);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected createPrefix(message: string) {
|
|
95
|
+
let prefix = `[${this.title}]`;
|
|
96
|
+
if (message) {
|
|
97
|
+
prefix += `[${message}] `;
|
|
98
|
+
} else {
|
|
99
|
+
prefix += ' ';
|
|
100
|
+
}
|
|
101
|
+
return prefix;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private wrapMessageAt<T extends keyof Omit<Console & { Console: any }, 'Console'>>(
|
|
105
|
+
original: T,
|
|
106
|
+
messageLoc: number,
|
|
107
|
+
additionalPrefix?: string
|
|
108
|
+
): Console[T] {
|
|
109
|
+
let prefix = `[${this.title}]`;
|
|
110
|
+
if (additionalPrefix) {
|
|
111
|
+
prefix += `[${additionalPrefix}] `;
|
|
112
|
+
} else {
|
|
113
|
+
prefix += ' ';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const fn = this.wrap(original);
|
|
117
|
+
|
|
118
|
+
return nameFunction('console:' + original, (...args: any[]) => {
|
|
119
|
+
this.convertObjectArg(args, messageLoc);
|
|
120
|
+
this.processColorLabel(args, messageLoc, original, prefix);
|
|
121
|
+
fn(...args);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private convertObjectArg(args: any[], pos: number) {
|
|
126
|
+
const msg = args[pos];
|
|
127
|
+
if (args.length > pos) {
|
|
128
|
+
if (typeof msg === 'string') {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
args.splice(pos, 0, (isWeb ? ' %o' : ' %j').repeat(args.length - pos).substr(1));
|
|
133
|
+
} else {
|
|
134
|
+
args[pos] = '';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
protected abstract processColorLabel(
|
|
139
|
+
normalizedArguments: any[],
|
|
140
|
+
messageLoc: number,
|
|
141
|
+
level: string,
|
|
142
|
+
prefix: string
|
|
143
|
+
): void;
|
|
144
|
+
|
|
145
|
+
protected uncolor(args: any[], pos: number, prefix: string, postfix: string) {
|
|
146
|
+
args[pos] = prefix + args[pos] + postfix;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** Find the index of given item */
|
|
2
|
+
export interface Finder<Type> {
|
|
3
|
+
(this: Type[], item: Type): number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
type MyFinder<Type> = (item: Type) => number;
|
|
7
|
+
|
|
8
|
+
export function RegexpFinder(this: RegExp[], item: RegExp): number {
|
|
9
|
+
return this.findIndex((e) => e.toString() === item.toString());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Like a Set, but use custom compare function insteadof ===
|
|
14
|
+
*/
|
|
15
|
+
export class CustomSet<Type = string> {
|
|
16
|
+
protected registry: Type[];
|
|
17
|
+
private finder: MyFinder<Type>;
|
|
18
|
+
|
|
19
|
+
constructor(finder: Finder<Type> = Array.prototype.indexOf) {
|
|
20
|
+
this.registry = [];
|
|
21
|
+
this.finder = finder.bind(this.registry);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setFinder(finder: Finder<Type>) {
|
|
25
|
+
this.finder = finder.bind(this.registry);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
has(item: Type): boolean {
|
|
29
|
+
return this.finder(item) !== -1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
add(item: Type): boolean {
|
|
33
|
+
const index = this.finder(item);
|
|
34
|
+
if (index === -1) {
|
|
35
|
+
this.registry.push(item);
|
|
36
|
+
return true;
|
|
37
|
+
} else {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @returns all added values
|
|
44
|
+
*/
|
|
45
|
+
addAll(items: Type[]): Type[] {
|
|
46
|
+
return items.filter((e) => this.add(e));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
delete(item: Type): boolean {
|
|
50
|
+
const index = this.finder(item);
|
|
51
|
+
if (index === -1) {
|
|
52
|
+
return false;
|
|
53
|
+
} else {
|
|
54
|
+
this.registry.splice(index, 1);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @returns all deleted values
|
|
61
|
+
*/
|
|
62
|
+
deleteAll(items: Type[]): Type[] {
|
|
63
|
+
return items.filter((e) => this.delete(e));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
clear() {
|
|
67
|
+
this.registry.length = 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get length() {
|
|
71
|
+
return this.registry.length;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get size() {
|
|
75
|
+
return this.registry.length;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
[Symbol.iterator](): Iterator<Type> {
|
|
79
|
+
return this.registry[Symbol.iterator]();
|
|
80
|
+
}
|
|
81
|
+
keys(): Iterator<Type> {
|
|
82
|
+
return this.registry[Symbol.iterator]();
|
|
83
|
+
}
|
|
84
|
+
values(): Iterator<Type> {
|
|
85
|
+
return this.registry[Symbol.iterator]();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
toArray() {
|
|
89
|
+
return this.registry.slice();
|
|
90
|
+
}
|
|
91
|
+
}
|