-
Notifications
You must be signed in to change notification settings - Fork 269
/
getStringyProps.ts
117 lines (103 loc) · 3.22 KB
/
getStringyProps.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import { remoteFunction, templateFunction } from '.';
const enum DescriptionSymbols {
// Our generic symbol
Generic = 'debug.description',
// Node.js-specific symbol that is used for some Node types https://nodejs.org/api/util.html#utilinspectcustom
Node = 'nodejs.util.inspect.custom',
}
/**
* Separate function that initializes description symbols. V8 considers
* Symbol.for as having a "side effect" and would throw if we tried to first
* use them inside the description functions.
*/
export const getDescriptionSymbols = remoteFunction(function () {
return [Symbol.for(DescriptionSymbols.Generic), Symbol.for(DescriptionSymbols.Node)];
});
declare const runtimeArgs: [symbol[]];
/**
* Gets a mapping of property names with a custom `.toString()` method
* to their string representations.
*/
export const getStringyProps = templateFunction(function (
this: unknown,
maxLength: number,
customToString: (defaultRepr: string) => unknown,
) {
const out: Record<string, string> = {};
const defaultPlaceholder = '<<default preview>>';
if (typeof this !== 'object' || !this) {
return out;
}
for (const [key, value] of Object.entries(this)) {
if (customToString) {
try {
const repr = customToString.call(value, defaultPlaceholder);
if (repr !== defaultPlaceholder) {
out[key] = String(repr);
continue;
}
} catch (e) {
out[key] = `<<indescribable>>${JSON.stringify([String(e), key])}`;
continue;
}
}
if (typeof value === 'object' && value) {
let str: string | undefined;
for (const sym of runtimeArgs[0]) {
try {
str = value[sym]();
break;
} catch {
// ignored
}
}
if (!str && !String(value.toString).includes('[native code]')) {
str = String(value);
}
if (str && !str.startsWith('[object ')) {
out[key] = str.length >= maxLength ? str.slice(0, maxLength) + '…' : str;
}
}
}
return out;
});
export const getToStringIfCustom = templateFunction(function (
this: unknown,
maxLength: number,
customToString: (defaultRepr: string) => unknown,
) {
if (customToString) {
try {
const defaultPlaceholder = '<<default preview>>';
const repr = customToString.call(this, defaultPlaceholder);
if (repr !== defaultPlaceholder) {
return String(repr);
}
} catch (e) {
return `<<indescribable>>${JSON.stringify([String(e), 'object'])}`;
}
}
if (typeof this === 'object' && this) {
let str: string | undefined;
for (const sym of [
Symbol.for(DescriptionSymbols.Generic),
Symbol.for(DescriptionSymbols.Node),
]) {
try {
str = (this as Record<symbol, () => string>)[sym]();
break;
} catch {
// ignored
}
}
if (!str && !String(this.toString).includes('[native code]')) {
str = String(this);
}
if (str && !str.startsWith('[object ')) {
return str.length >= maxLength ? str.slice(0, maxLength) + '…' : str;
}
}
});