@idlebox/common 1.5.13 → 1.5.15
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/lib/autoindex.d.ts +5 -3
- package/lib/autoindex.d.ts.map +1 -1
- package/lib/autoindex.js +70 -66
- package/lib/autoindex.js.map +1 -1
- package/lib/debugging/inspect.d.ts +2 -0
- package/lib/debugging/inspect.d.ts.map +1 -1
- package/lib/debugging/inspect.js +20 -8
- package/lib/debugging/inspect.js.map +1 -1
- package/lib/error/pretty.nodejs.d.ts +0 -29
- package/lib/error/pretty.nodejs.d.ts.map +1 -1
- package/lib/error/pretty.nodejs.js +157 -237
- package/lib/error/pretty.nodejs.js.map +1 -1
- package/lib/error/stack-parser.v8.d.ts +31 -0
- package/lib/error/stack-parser.v8.d.ts.map +1 -0
- package/lib/error/stack-parser.v8.js +106 -0
- package/lib/error/stack-parser.v8.js.map +1 -0
- package/lib/lifecycle/dispose/bridges/function.d.ts.map +1 -1
- package/lib/lifecycle/dispose/bridges/function.js +5 -2
- package/lib/lifecycle/dispose/bridges/function.js.map +1 -1
- package/lib/lifecycle/dispose/bridges/streams.d.ts.map +1 -1
- package/lib/lifecycle/dispose/bridges/streams.js +9 -4
- package/lib/lifecycle/dispose/bridges/streams.js.map +1 -1
- package/lib/lifecycle/dispose/disposable.d.ts.map +1 -1
- package/lib/lifecycle/dispose/disposable.js +11 -1
- package/lib/lifecycle/dispose/disposable.js.map +1 -1
- package/lib/lifecycle/event/event.d.ts +2 -0
- package/lib/lifecycle/event/event.d.ts.map +1 -1
- package/lib/lifecycle/event/event.js +15 -1
- package/lib/lifecycle/event/event.js.map +1 -1
- package/lib/schedule/interval.d.ts +2 -0
- package/lib/schedule/interval.d.ts.map +1 -1
- package/lib/schedule/interval.js +11 -0
- package/lib/schedule/interval.js.map +1 -1
- package/package.json +7 -7
- package/src/autoindex.ts +94 -90
- package/src/debugging/inspect.ts +24 -4
- package/src/error/pretty.nodejs.ts +214 -337
- package/src/error/stack-parser.v8.ts +157 -0
- package/src/lifecycle/dispose/bridges/function.ts +11 -5
- package/src/lifecycle/dispose/bridges/streams.ts +47 -36
- package/src/lifecycle/dispose/disposable.ts +14 -1
- package/src/lifecycle/event/event.ts +18 -1
- package/src/schedule/interval.ts +12 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { isAbsolute } from '../path/isAbsolute.js';
|
|
2
|
+
|
|
3
|
+
const padding = /^(?<padding> {4})at /.source;
|
|
4
|
+
const func_call = /(?<func_name>(?:(?:async|new) )?[^/\\\s]+) (?:\[as (?<func_alias>[^\]]+)] )?/.source;
|
|
5
|
+
// xxxx.yyyyy [as eval]
|
|
6
|
+
const line_column = /(?::(?<line>\d+))?(?::(?<column>\d+))?/.source;
|
|
7
|
+
const locationEsm = /(?<schema>node:|file:\/\/|https?:\/\/)?(?<path2>[^:]+)/.source;
|
|
8
|
+
// node:internal/modules/cjs/loader.js:883:14
|
|
9
|
+
const locationCjs = /(?<path1>(?:\/|[a-zA-Z]:)[^:]+)/.source;
|
|
10
|
+
// /data/to/file.js
|
|
11
|
+
const location = `(?:${locationCjs}|${locationEsm})${line_column}`;
|
|
12
|
+
|
|
13
|
+
const regNormal = new RegExp(`${padding}${func_call}\\(${location}\\)$`);
|
|
14
|
+
type TypeMatchNormal = 'padding' | TypeMatchNoFile | TypeMatchFileOnly;
|
|
15
|
+
|
|
16
|
+
const regNoFile = new RegExp(`${padding}${func_call}$`);
|
|
17
|
+
type TypeMatchNoFile = 'padding' | 'func_name' | 'func_alias';
|
|
18
|
+
|
|
19
|
+
const regFileOnly = new RegExp(`${padding}${location}$`);
|
|
20
|
+
type TypeMatchFileOnly = 'padding' | 'schema' | 'path1' | 'path2' | 'line' | 'column';
|
|
21
|
+
|
|
22
|
+
const regEvalItem = new RegExp(`\\(eval at ${func_call}`, 'g');
|
|
23
|
+
const eval_source = /, (?<eval_func>[\S]+):(?<eval_line>\d+):(?<eval_column>\d+)/.source;
|
|
24
|
+
const regEval = new RegExp(`${padding}${func_call}.*?\\(${location}\\)+${eval_source}`);
|
|
25
|
+
type TypeMatchEval = 'padding' | TypeMatchNoFile | TypeMatchFileOnly | 'eval_func' | 'eval_line' | 'eval_column';
|
|
26
|
+
|
|
27
|
+
const regInvalid = new RegExp(`${padding}(?<content>.+) \\(${location}\\)$`);
|
|
28
|
+
type TypeMatchInvalid = TypeMatchFileOnly | 'content';
|
|
29
|
+
|
|
30
|
+
export function parseStackString(stack: string) {
|
|
31
|
+
return stack.split('\n').map(parseStackLine);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface IFunction {
|
|
35
|
+
name: string;
|
|
36
|
+
alias?: string;
|
|
37
|
+
}
|
|
38
|
+
interface IFileLocation {
|
|
39
|
+
path: string;
|
|
40
|
+
schema: string; // '' | 'node:' | 'file:' | 'http:' | 'https:';
|
|
41
|
+
line: number;
|
|
42
|
+
column: number;
|
|
43
|
+
isAbsolute: boolean;
|
|
44
|
+
}
|
|
45
|
+
interface IEvalDef {
|
|
46
|
+
eval_func: string;
|
|
47
|
+
eval_line: number;
|
|
48
|
+
eval_column: number;
|
|
49
|
+
funcs: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface IStructreStackLine {
|
|
53
|
+
invalid?: boolean;
|
|
54
|
+
special?: boolean;
|
|
55
|
+
toString(): string;
|
|
56
|
+
padding?: string;
|
|
57
|
+
func?: IFunction;
|
|
58
|
+
location?: IFileLocation;
|
|
59
|
+
eval?: IEvalDef;
|
|
60
|
+
_matches?: RegExp;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function matchLine<T extends string>(line: string, reg: RegExp): null | Record<T, string> {
|
|
64
|
+
const m = reg.exec(line);
|
|
65
|
+
if (!m) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return m.groups as any;
|
|
69
|
+
}
|
|
70
|
+
const endingSlashes = /\/+$/;
|
|
71
|
+
function addLoc(ret: IStructreStackLine, m: Record<TypeMatchFileOnly, string>) {
|
|
72
|
+
const path = m.path1 || m.path2;
|
|
73
|
+
ret.location = {
|
|
74
|
+
schema: m.schema?.replace(endingSlashes, '') ?? '',
|
|
75
|
+
path: path,
|
|
76
|
+
line: Number.parseInt(m.line, 10),
|
|
77
|
+
column: Number.parseInt(m.column, 10),
|
|
78
|
+
isAbsolute: isAbsolute(path),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function addFunc(ret: IStructreStackLine, m: Record<TypeMatchNoFile, string>) {
|
|
83
|
+
ret.func = {
|
|
84
|
+
name: m.func_name,
|
|
85
|
+
alias: m.func_alias,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function parseStackLine(line: string): IStructreStackLine {
|
|
90
|
+
const __raw = line;
|
|
91
|
+
const ret: IStructreStackLine = {
|
|
92
|
+
invalid: false,
|
|
93
|
+
toString() {
|
|
94
|
+
return __raw;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
Object.assign(ret, { __raw });
|
|
98
|
+
|
|
99
|
+
const mNormal = matchLine<TypeMatchNormal>(line, regNormal);
|
|
100
|
+
if (mNormal) {
|
|
101
|
+
ret._matches = regNormal;
|
|
102
|
+
ret.padding = mNormal.padding;
|
|
103
|
+
addFunc(ret, mNormal);
|
|
104
|
+
addLoc(ret, mNormal);
|
|
105
|
+
return ret;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const mFile = matchLine<TypeMatchFileOnly>(line, regFileOnly);
|
|
109
|
+
if (mFile) {
|
|
110
|
+
ret._matches = regFileOnly;
|
|
111
|
+
ret.padding = mFile.padding;
|
|
112
|
+
addLoc(ret, mFile);
|
|
113
|
+
return ret;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const mNoFile = matchLine<TypeMatchNoFile>(line, regNoFile);
|
|
117
|
+
if (mNoFile) {
|
|
118
|
+
ret._matches = regNoFile;
|
|
119
|
+
ret.padding = mNoFile.padding;
|
|
120
|
+
addFunc(ret, mNoFile);
|
|
121
|
+
return ret;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const mEval = matchLine<TypeMatchEval>(line.replaceAll(regEvalItem, ''), regEval);
|
|
125
|
+
if (mEval) {
|
|
126
|
+
ret._matches = regEval;
|
|
127
|
+
ret.padding = mEval.padding;
|
|
128
|
+
addFunc(ret, mEval);
|
|
129
|
+
addLoc(ret, mEval);
|
|
130
|
+
|
|
131
|
+
ret.eval = {
|
|
132
|
+
eval_column: Number.parseInt(mEval.eval_column, 10),
|
|
133
|
+
eval_func: mEval.eval_func,
|
|
134
|
+
eval_line: Number.parseInt(mEval.eval_line, 10),
|
|
135
|
+
funcs: [],
|
|
136
|
+
};
|
|
137
|
+
for (const item of line.matchAll(regEvalItem)) {
|
|
138
|
+
// biome-ignore lint/style/noNonNullAssertion: 有匹配必然有 groups
|
|
139
|
+
ret.eval.funcs.push(item.groups!['func_name']);
|
|
140
|
+
}
|
|
141
|
+
ret.eval.funcs.push(mEval.eval_func);
|
|
142
|
+
|
|
143
|
+
return ret;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const mInv = matchLine<TypeMatchInvalid>(line, regInvalid);
|
|
147
|
+
if (mInv) {
|
|
148
|
+
const path = mInv.path1 || mInv.path2;
|
|
149
|
+
if (path.endsWith(mInv.content)) {
|
|
150
|
+
addLoc(ret, mInv);
|
|
151
|
+
return ret;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
ret.invalid = true;
|
|
156
|
+
return ret;
|
|
157
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineInspectMethod } from '../../../debugging/inspect.js';
|
|
1
2
|
import { functionName, nameObject } from '../../../debugging/object-with-name.js';
|
|
2
3
|
import { dispose_name } from '../debug.js';
|
|
3
4
|
import type { IAsyncDisposable, IDisposable } from '../disposable.js';
|
|
@@ -7,12 +8,17 @@ import type { IAsyncDisposable, IDisposable } from '../disposable.js';
|
|
|
7
8
|
* @public
|
|
8
9
|
*/
|
|
9
10
|
export function functionToDisposable<RT>(fn: () => RT): RT extends Promise<any> ? IAsyncDisposable : IDisposable {
|
|
10
|
-
return
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
return defineInspectMethod(
|
|
12
|
+
{
|
|
13
|
+
get displayName() {
|
|
14
|
+
return `disposeFn(${functionName(fn)})`;
|
|
15
|
+
},
|
|
16
|
+
dispose: fn,
|
|
17
|
+
} as any,
|
|
18
|
+
(_depth, options) => {
|
|
19
|
+
return options.stylize(`[FunctionDisposable ${functionName(fn)}]`, 'special');
|
|
13
20
|
},
|
|
14
|
-
|
|
15
|
-
} as any;
|
|
21
|
+
);
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineInspectMethod } from '../../../debugging/inspect.js';
|
|
1
2
|
import { objectName } from '../../../debugging/object-with-name.js';
|
|
2
3
|
import type { IAsyncDisposable } from '../disposable.js';
|
|
3
4
|
|
|
@@ -13,26 +14,31 @@ type ClosableAsync = {
|
|
|
13
14
|
export function closableToDisposable<T extends ClosableAsync>(closable: T): IAsyncDisposable {
|
|
14
15
|
const promised = closable.close.length === 0;
|
|
15
16
|
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
return defineInspectMethod(
|
|
18
|
+
{
|
|
19
|
+
get displayName() {
|
|
20
|
+
return `closable(${objectName(closable) || 'unknown'})`;
|
|
21
|
+
},
|
|
22
|
+
dispose(): Promise<void> {
|
|
23
|
+
if (promised) {
|
|
24
|
+
return Promise.resolve(closable.close()).then(() => undefined);
|
|
25
|
+
} else {
|
|
26
|
+
return new Promise<void>((resolve, reject) => {
|
|
27
|
+
closable.close((error) => {
|
|
28
|
+
if (error) {
|
|
29
|
+
reject(error);
|
|
30
|
+
} else {
|
|
31
|
+
resolve();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
31
34
|
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
(_depth, options) => {
|
|
39
|
+
return options.stylize(`[ClosableDisposable ${objectName(closable) || 'unknown'}]`, 'special');
|
|
34
40
|
},
|
|
35
|
-
|
|
41
|
+
);
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
type EndableAsync = {
|
|
@@ -47,24 +53,29 @@ type EndableAsync = {
|
|
|
47
53
|
export function endableToDisposable<T extends EndableAsync>(endable: T): IAsyncDisposable {
|
|
48
54
|
const promised = endable.end.length === 0;
|
|
49
55
|
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
return defineInspectMethod(
|
|
57
|
+
{
|
|
58
|
+
get displayName() {
|
|
59
|
+
return `endable(${objectName(endable) || 'unknown'})`;
|
|
60
|
+
},
|
|
61
|
+
dispose(): Promise<void> {
|
|
62
|
+
if (promised) {
|
|
63
|
+
return Promise.resolve(endable.end()).then(() => undefined);
|
|
64
|
+
} else {
|
|
65
|
+
return new Promise<void>((resolve, reject) => {
|
|
66
|
+
return endable.end((error) => {
|
|
67
|
+
if (error) {
|
|
68
|
+
reject(error);
|
|
69
|
+
} else {
|
|
70
|
+
resolve();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
65
73
|
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
(_depth, options) => {
|
|
78
|
+
return options.stylize(`[EndableDisposable ${objectName(endable) || 'unknown'}]`, 'special');
|
|
68
79
|
},
|
|
69
|
-
|
|
80
|
+
);
|
|
70
81
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineInspectMethod } from '../../debugging/inspect.js';
|
|
1
2
|
import type { MaybeNamed } from '../../debugging/object-with-name.js';
|
|
2
3
|
import { createStackTraceHolder, type StackTraceHolder } from '../../error/stack-trace.js';
|
|
3
4
|
import { Emitter } from '../event/event.js';
|
|
@@ -57,13 +58,25 @@ export abstract class AbstractEnhancedDisposable<Async extends boolean> implemen
|
|
|
57
58
|
this.displayName = displayName;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
this._logger = _debug_dispose.extend(this.displayName || 'disposable')
|
|
61
|
+
this._logger = defineInspectMethod(_debug_dispose.extend(this.displayName || 'disposable'), () => {
|
|
62
|
+
return `[Function debug]`;
|
|
63
|
+
});
|
|
61
64
|
|
|
62
65
|
this._onPostDispose.handle(() => {
|
|
63
66
|
this._onPostDispose.dispose();
|
|
64
67
|
});
|
|
65
68
|
this._disposables.push(this._onBeforeDispose);
|
|
66
69
|
this._disposables.push(this._onDisposeError);
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
this.constructor.name === 'EnhancedAsyncDisposable' ||
|
|
73
|
+
this.constructor.name === 'UnorderedAsyncDisposable' ||
|
|
74
|
+
this.constructor.name === 'EnhancedDisposable'
|
|
75
|
+
) {
|
|
76
|
+
defineInspectMethod(this, (_depth: number, options: any) => {
|
|
77
|
+
return options.stylize(`[${this.displayName}]`, 'special');
|
|
78
|
+
});
|
|
79
|
+
}
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Exit } from '@idlebox/errors';
|
|
2
|
+
import { defineInspectMethod, inspectSymbol } from '../../debugging/inspect.js';
|
|
2
3
|
import { nameObject, objectName } from '../../debugging/object-with-name.js';
|
|
3
4
|
import { createStackTraceHolder } from '../../error/stack-trace.js';
|
|
4
5
|
import { functionToDisposable } from '../dispose/bridges/function.js';
|
|
@@ -6,6 +7,8 @@ import type { IDisposable } from '../dispose/disposable.js';
|
|
|
6
7
|
import { DisposedError } from '../dispose/disposedError.js';
|
|
7
8
|
import type { EventHandler, EventRegister, IEventEmitter } from './type.js';
|
|
8
9
|
|
|
10
|
+
const anonymousName = 'AnonymousEmitter';
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* @public
|
|
11
14
|
*/
|
|
@@ -14,7 +17,7 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
|
|
|
14
17
|
private executing = false;
|
|
15
18
|
private _something_change_during_call = false;
|
|
16
19
|
|
|
17
|
-
constructor(public readonly displayName: string =
|
|
20
|
+
constructor(public readonly displayName: string = anonymousName) {
|
|
18
21
|
this.handle = Object.defineProperties(this.handle.bind(this), {
|
|
19
22
|
once: {
|
|
20
23
|
get: () => this.once.bind(this),
|
|
@@ -26,6 +29,9 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
|
|
|
26
29
|
get: () => this._disposed,
|
|
27
30
|
},
|
|
28
31
|
});
|
|
32
|
+
defineInspectMethod(this.handle, (_depth, options) => {
|
|
33
|
+
return options.stylize(`[EmitterRegister ${this.displayName}]`, 'special');
|
|
34
|
+
});
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
public listenerCount() {
|
|
@@ -181,6 +187,17 @@ export class Emitter<T = unknown> implements IEventEmitter<T> {
|
|
|
181
187
|
|
|
182
188
|
readonly [Symbol.dispose] = this.dispose;
|
|
183
189
|
|
|
190
|
+
[inspectSymbol](_depth: number, options: any) {
|
|
191
|
+
let r = `${options.stylize(this.constructor.name, 'name')} {`;
|
|
192
|
+
if (this.displayName !== anonymousName) {
|
|
193
|
+
r += ` ${options.stylize(this.displayName, 'string')},`;
|
|
194
|
+
}
|
|
195
|
+
r += ` listeners: ${options.stylize(this.listenerCount(), 'number')}`;
|
|
196
|
+
|
|
197
|
+
r += ' }';
|
|
198
|
+
return r;
|
|
199
|
+
}
|
|
200
|
+
|
|
184
201
|
private requireNotExecuting() {
|
|
185
202
|
if (this.executing) {
|
|
186
203
|
throw new Error('conflict state, emitter is firing');
|
package/src/schedule/interval.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inspectSymbol } from '../debugging/inspect.js';
|
|
1
2
|
import { objectName } from '../debugging/object-with-name.js';
|
|
2
3
|
import type { IDisposable } from '../lifecycle/dispose/disposable.js';
|
|
3
4
|
import { EnhancedDisposable } from '../lifecycle/dispose/sync-disposable.js';
|
|
@@ -61,4 +62,15 @@ export class Interval extends EnhancedDisposable {
|
|
|
61
62
|
if (this.timer) this.timer.dispose();
|
|
62
63
|
return super.dispose();
|
|
63
64
|
}
|
|
65
|
+
|
|
66
|
+
[inspectSymbol](depth: number, options: any, inspect: any) {
|
|
67
|
+
if (depth < 0) {
|
|
68
|
+
return options.stylize(`[Interval ${this.ms}ms]`, 'special');
|
|
69
|
+
}
|
|
70
|
+
let r = `${options.stylize(this.constructor.name, 'name')} ${options.stylize(`${this.ms}`, 'number')}ms`;
|
|
71
|
+
const padding = ' '.repeat(2);
|
|
72
|
+
const inner = inspect(this._emitter, options, inspect).replace(/\n/g, `\n${padding}`);
|
|
73
|
+
r += ` {\n${padding}onTick: ${inner}\n}`;
|
|
74
|
+
return r;
|
|
75
|
+
}
|
|
64
76
|
}
|