-
Notifications
You must be signed in to change notification settings - Fork 1
/
code-map.js
114 lines (91 loc) · 2.59 KB
/
code-map.js
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
const stream = require('stream');
const crypto = require('crypto');
const fs = require('fs');
const Generator = Object.getPrototypeOf(function* f() { return false; }()).constructor;
// const GeneratorFunction = Object.getPrototypeOf(function* f() { return false; }).constructor;
const nodeIgnore = [
require.cache,
require.extensions,
require.main,
global.async_hooks,
];
const deprecated = new WeakMap([
[global, new Set([
'GLOBAL',
'root',
])],
[process, new Set([
'EventEmitter',
])],
[crypto, new Set([
'createCredentials',
'Credentials',
])],
[stream.Stream.Writable.WritableState.prototype, new Set([
'buffer',
])],
[fs, new Set([
'SyncWriteStream',
])],
]);
// TODO make this more simple with only one level: obj->prop
class CodeMap extends WeakMap {
static getPropValue(obj, propName) {
try {
return obj[propName];
} catch (err) {
return null;
}
}
static pathCompare(a, b) {
if (a.length !== b.length) {
return a.length - b.length;
}
const aStr = a.filter(str => typeof str === 'string').join();
const bStr = b.filter(str => typeof str === 'string').join();
return aStr.length - bStr.length;
}
constructor(opts = {}) {
const scan = opts.scan || global;
super([
[scan, opts.path || ['global']],
]);
if (opts.sharedObjects) {
opts.sharedObjects.forEach((obj, path) => this.add(obj, path));
}
this.scanned = new WeakSet(opts.ignore || []);
if (opts.node !== false) {
for (const obj of nodeIgnore) {
if (obj) this.scanned.add(obj);
}
}
this.scan(scan, opts.path || []);
if (scan === global) {
this.scan(Generator.prototype, ['(function*(){})()']);
// this.scan(GeneratorFunction, 'Object.getPrototypeOf(function*(){}).constructor');
}
}
add(obj, path) {
this.set(obj, path);
this.scanned.add(obj);
}
scan(obj, path) {
if (obj === null) return;
const type = typeof obj;
if (type !== 'object' && type !== 'function') return;
if (!this.scanned.has(obj)) {
this.scanned.add(obj);
} else if (path.length) {
const currPath = this.get(obj);
if (!currPath || this.constructor.pathCompare(currPath, path) <= 0) return;
}
if (path.length) this.add(obj, path);
const deprecates = deprecated.get(obj);
Object.getOwnPropertyNames(obj).forEach(propName => {
if (deprecates && deprecates.has(propName)) return;
const prop = this.constructor.getPropValue(obj, propName);
this.scan(prop, path.concat(propName));
});
}
}
module.exports = CodeMap;