Open Jack-Works opened 2 years ago
I feel like it would simpler to go with one of the previous ideas where there was an actual Global
constructor that made new global objects. This means the host could just perform the population of the global object for the user i.e.:
// Creates a new global object with the appropriate
// intrinsics already attached
const g = new Global();
g.Array === Array; // true
const e = new Evaluator({ global: g });
e.eval(`Math`); // object Math { ... }
Customizing these globals wouldn't be particularly hard, just an Object.assign
or similar:
const e = new Evaluator({
global: Object.assign(new Global(), {
myApi: () => { ... },
}),
});
If there's desire for exotic behaviour (i.e. #38) one could just allow new Global()
to take proxy traps:
const fakeDocument = new FakeDocument();
const g = new Global({
// proxy hooks...
get(global, prop, receiver) {
},
});
I feel like the questions about e.eval("Evaluator")
is a much wider problem than just inheriting, like the point of having say evaluator.Function !== Function
is so that new Function("return someGlobal")
has the right evaluator, but this becomes weird given that inherited intrinsics will have the original Function
i.e.:
const g = new Global();
const e = new Evaluator({
// the following problem is independent on this API shape
global: g,
});
// Set the Function global
g.Function = e.Function;
// Multiple Function constructors floating around in the same evaluator
e.eval(`
Function === Array.constructor; // false
`);
// And so code run inside the evaluator can still access parent globals fairly unrestrictedly
e.eval(`
const OuterFunction = Array.constructor;
const OuterModule = new OuterFunction("return Module");
const module = new OuterModule(new ModuleSourceText(`
// do thing in the parent evaluator's global scope
`)):
`);
I don't see any obvious way to repair this if we allow multiple Function
in particular to exist within the same evaluator.
Nevermind this, I thought .constructor
was an own property on builtin functions, but it's actually just inherited from Function.prototype.constructor
.
Nevermind this, I thought
.constructor
was an own property on builtin functions, but it's actually just inherited fromFunction.prototype.constructor
.
Actually no this is still a problem, Array.constructor
can't be e.Function
, as the outer and inner Array.constructor
need to agree:
const g = CREATE_GLOBAL_SOMEHOW();
const e = new Evaluator({ global: g });
g.Function = e.Function;
// If this agrees:
Array === e.eval(`Array`); // true
// then so must
Array.constructor === e.eval(`Array.constructor`); // true
// hence Array.constructor is the outer Function
Function === e.eval(`Array.constructor`); // true
The only way for this not to agree would be if Function.prototype.constructor
actually checked the caller's evaluator, although other than direct eval
this is unlike simply calling a function (.prototype.[[Get]](...)
) would usually be capable of doing.
My intent is that whomever creates the intrinsics is in a position to arrange the new intrinsics however they see fit, and that the common case would be:
const localThis = Object.create(globalThis);
const evaluators = new Evaluators(localThis);
Object.assign(localThis, evaluators);
Such that direct eval would work as-expected in evaluated code. This would be sufficient for the DSL usecase.
This is not very different from a Global
constructor, except that it allows for the possibility of:
const evaluators = new Evaluators(globalThis, { importHook, importMeta });
Where the globalThis is object identical to the surrounding environment but import behavior is virtualized. I imagine this to be a common need as well. This would have the surprising but probably okay side-effect of disabling direct eval. That could of course be recovered if it’s actually needed, by binding eval
lexically, as in:
new evaluators.Function('eval', 'text', 'eval(text)')(evaluators.eval, text);
I’m not strongly partial to either Global
, Evaluators
, or just lockdown Compartment
. Any of these are sufficient for isolating dependencies or other guest programs.