-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathlocal.js
105 lines (97 loc) · 2.71 KB
/
local.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
const { details: X, quote: q } = assert;
const { getOwnPropertyDescriptors, getPrototypeOf, freeze } = Object;
const { apply, ownKeys } = Reflect;
const ntypeof = specimen => (specimen === null ? 'null' : typeof specimen);
/**
* TODO Consolidate with `isObject` that's currently in `@endo/marshal`
*
* @param {any} val
* @returns {boolean}
*/
const isObject = val => Object(val) === val;
/**
* Prioritize symbols as earlier than strings.
*
* @param {string|symbol} a
* @param {string|symbol} b
* @returns {-1 | 0 | 1}
*/
const compareStringified = (a, b) => {
if (typeof a === typeof b) {
const left = String(a);
const right = String(b);
// eslint-disable-next-line no-nested-ternary
return left < right ? -1 : left > right ? 1 : 0;
}
if (typeof a === 'symbol') {
assert(typeof b === 'string');
return -1;
}
assert(typeof a === 'string');
assert(typeof b === 'symbol');
return 1;
};
/**
* @param {any} val
* @returns {(string|symbol)[]}
*/
export const getMethodNames = val => {
let layer = val;
const names = new Set(); // Set to deduplicate
while (layer !== null && layer !== Object.prototype) {
// be tolerant of non-objects
const descs = getOwnPropertyDescriptors(layer);
for (const name of ownKeys(descs)) {
// In case a method is overridden by a non-method,
// test `val[name]` rather than `layer[name]`
if (typeof val[name] === 'function') {
names.add(name);
}
}
if (!isObject(val)) {
break;
}
layer = getPrototypeOf(layer);
}
return harden([...names].sort(compareStringified));
};
// The top level of the eventual send modules can be evaluated before
// ses creates `harden`, and so cannot rely on `harden` at top level.
freeze(getMethodNames);
export const localApplyFunction = (t, args) => {
assert.typeof(
t,
'function',
X`Cannot invoke target as a function; typeof target is ${q(ntypeof(t))}`,
);
return apply(t, undefined, args);
};
export const localApplyMethod = (t, method, args) => {
if (method === undefined || method === null) {
// Base case; bottom out to apply functions.
return localApplyFunction(t, args);
}
if (t === undefined || t === null) {
assert.fail(
X`Cannot deliver ${q(method)} to target; typeof target is ${q(
ntypeof(t),
)}`,
TypeError,
);
}
const fn = t[method];
if (fn === undefined) {
assert.fail(
X`target has no method ${q(method)}, has ${q(getMethodNames(t))}`,
TypeError,
);
}
const ftype = ntypeof(fn);
assert.typeof(
fn,
'function',
X`invoked method ${q(method)} is not a function; it is a ${q(ftype)}`,
);
return apply(fn, t, args);
};
export const localGet = (t, key) => t[key];