-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
inspect.ts
120 lines (107 loc) · 3.09 KB
/
inspect.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
118
119
120
import { _WeakSet as WeakSet } from '@ember/polyfills';
const { toString: objectToString } = Object.prototype;
const { toString: functionToString } = Function.prototype;
const { isArray } = Array;
const { keys: objectKeys } = Object;
const { stringify } = JSON;
const LIST_LIMIT = 100;
const DEPTH_LIMIT = 4;
const SAFE_KEY = /^[\w$]+$/;
/**
@module @ember/debug
*/
/**
Convenience method to inspect an object. This method will attempt to
convert the object into a useful string description.
It is a pretty simple implementation. If you want something more robust,
use something like JSDump: https://github.com/NV/jsDump
@method inspect
@static
@param {Object} obj The object you want to inspect.
@return {String} A description of the object
@since 1.4.0
@private
*/
export default function inspect(this: any, obj: any | null | undefined): string {
// detect Node util.inspect call inspect(depth: number, opts: object)
if (typeof obj === 'number' && arguments.length === 2) {
return this;
}
return inspectValue(obj, 0);
}
function inspectValue(value: any | null | undefined, depth: number, seen?: WeakSet<object>) {
let valueIsArray = false;
switch (typeof value) {
case 'undefined':
return 'undefined';
case 'object':
if (value === null) return 'null';
if (isArray(value)) {
valueIsArray = true;
break;
}
// is toString Object.prototype.toString or undefined then traverse
if (value.toString === objectToString || value.toString === undefined) {
break;
}
// custom toString
return value.toString();
case 'function':
return value.toString === functionToString
? value.name ? `[Function:${value.name}]` : `[Function]`
: value.toString();
case 'string':
return stringify(value);
case 'symbol':
case 'boolean':
case 'number':
default:
return value.toString();
}
if (seen === undefined) {
seen = new WeakSet();
} else {
if (seen.has(value)) return `[Circular]`;
}
seen.add(value);
return valueIsArray
? inspectArray(value, depth + 1, seen)
: inspectObject(value, depth + 1, seen);
}
function inspectKey(key: string) {
return SAFE_KEY.test(key) ? key : stringify(key);
}
function inspectObject(obj: object, depth: number, seen: WeakSet<object>) {
if (depth > DEPTH_LIMIT) {
return '[Object]';
}
let s = '{';
let keys = objectKeys(obj);
for (let i = 0; i < keys.length; i++) {
s += i === 0 ? ' ' : ', ';
if (i >= LIST_LIMIT) {
s += `... ${keys.length - LIST_LIMIT} more keys`;
break;
}
let key = keys[i];
s += inspectKey(key) + ': ' + inspectValue(obj[key], depth, seen);
}
s += ' }';
return s;
}
function inspectArray(arr: any[], depth: number, seen: WeakSet<object>) {
if (depth > DEPTH_LIMIT) {
return '[Array]';
}
let s = '[';
for (let i = 0; i < arr.length; i++) {
s += i === 0 ? ' ' : ', ';
if (i >= LIST_LIMIT) {
s += `... ${arr.length - LIST_LIMIT} more items`;
break;
}
s += inspectValue(arr[i], depth, seen);
}
s += ' ]';
return s;
}