slides#4
Conversation
|
The rendered spec for this PR is available at https://endojs.github.io/proposal-new-global/pr/4. |
| AsyncFunction: typeof AsyncFunction, | ||
| GeneratorFunction: typeof GeneratorFunction, | ||
| AsyncGeneratorFunction: typeof AsyncGeneratorFunction, |
There was a problem hiding this comment.
I’m not sure how we would express that the new global would have unique versions of these intrinsics, but that they would not be own properties of the new global. They are accessible by evaluating syntax using the eval of the global. It might be good to add an Intersection Semantics section for Jordan’s Get Intrinsics proposal. My expectation is that newGlobal.getIntrinsic by whatever name, would also be a unique own property of each new global, and be able to address %AsyncFunction% and %AsyncFunctionPrototype% directly from internal slots of the global.
| const thatGlobal = new globalThis.Global({ | ||
| keys: ['Buffer'], | ||
| importHook, | ||
| importMeta, | ||
| }); | ||
|
|
||
| thatGlobal.process = { env: process.env } |
There was a problem hiding this comment.
Maybe we should spell these like newGlobal so newGlobal.globalThis is not confusing.
There was a problem hiding this comment.
that is almost a keyword for me from the times of arrow functions not being available and the popularity of Backbone and other class emulation, but the more times we can repeat the sequence new Global the better.
| Global: typeof Global, | ||
| eval: typeof eval, | ||
| Function: typeof Function, | ||
| // and all permutations of Async and Generator |
There was a problem hiding this comment.
| // and all permutations of Async and Generator |
Oddly enough, all of the properties of the new global are covered by keys of the old global. Calling these three out just reïnforces the notion that they are not identical, where the others are, and that all the permutations on function constructor are also non-identical. We might need to turn to a single specific example of newGlobal.eval to make that point clear.
(async () => {}).constructor !==
new Global().eval('async () => {}').constructorThere was a problem hiding this comment.
addressed it in details slide
| > It also eliminates the concern where evaluators accepting any globalThis to use would clash with the host implementation's desire to use special objects only the host can create. | ||
| > No API to set a custom reference as global context for evaluators if it's not created via `new Global` | ||
| > When a new global is created it inherits all properties from parent global unless user specifies a list. Spec offers no opinions on minimal global, only demands that all evaluators are present. | ||
| --- |
There was a problem hiding this comment.
We need to take a position on the prototype chain of new global.
There was a problem hiding this comment.
I know we do. I'm not sure now is the time.
There was a problem hiding this comment.
I don't see how the prototype chain could become anything other than a reference to the same prototype chain that was originally there and for the isolation/sandboxing usecase it could be replaced or hardened depending on the needs.
Some complications around window.on etc. that are methods on the prototype is what we need to take into account
| ### Details - invariants | ||
| ```js | ||
| globalThis.x = {}; | ||
| const thatGlobal = new globalThis.Global({ | ||
| keys: Object.keys(globalThis), | ||
| }); | ||
| thatGlobal.eval !== thisGlobal.eval; | ||
| thatGlobal.Global !== thisGlobal.Global; | ||
| thatGlobal.Function !== thisGlobal.Function; | ||
| thatGlobal.eval("Object.getPrototypeOf(async () => {})") !== | ||
| Object.getPrototypeOf(async () => {}); | ||
| thatGlobal.eval("Object.getPrototypeOf(function *() {})") !== | ||
| Object.getPrototypeOf(function* () {}); | ||
| thatGlobal.eval("Object.getPrototypeOf(async function *() {})") !== | ||
| Object.getPrototypeOf(async function* () {}); | ||
| const source = new ModuleSource("export default {}"); | ||
| (await thatGlobal.eval("(...args) => import(...args)")(source)) !== | ||
| (await import(source)); | ||
| thatGlobal.ModuleSource === thisGlobal.ModuleSource; | ||
| thatGlobal.Array === thisGlobal.Array; | ||
| thatGlobal.x === thisGlobal.x; |
There was a problem hiding this comment.
All properties grafted by default
globalThis.x = {};
const newGlobal = new globalThis.Global();
newGlobal.Object === globalThis.Object;
newGlobal.x === globalThis.x;Properties can be selectively grafted
globalThis.x = {};
const newGlobal = new Global({
keys: [],
});
newGlobal.x === undefined;Some properties undeniable
const newGlobal = new Global({
keys: []
});
newGlobal.Object === globalThis.Object;Own unique evaluators
const newGlobal = new Global();
newGlobal.eval !== thisGlobal.eval;
newGlobal.Global !== thisGlobal.Global;
newGlobal.Function !== thisGlobal.Function;Other unique intrinsic evaluators
const newGlobal = new Global();
newGlobal.eval("Object.getPrototypeOf(async () => {})") !==
Object.getPrototypeOf(async () => {});
newGlobal.eval("Object.getPrototypeOf(function *() {})") !==
Object.getPrototypeOf(function* () {});
newGlobal.eval("Object.getPrototypeOf(async function *() {})") !==
Object.getPrototypeOf(async function* () {});Inherits host import hook and module map by default
const newGlobal = new Global();
const fs1 = await import("node:fs");
const fs2 = await newGlobal.eval('import("node:fs")');
fs1 === fs2; // if presentCan override import hook
const newGlobal = new Global({
async importHook(specifier) {
if (specifier === 'node:fs') {
return import.source('mock-fs.js');
} else {
return import.source(specifier);
}
}
});
const fs = await newGlobal.eval('import("node:fs"))');Closed holes
const fs = await (0, eval)('import("node:fs");const AsyncFunction = (async () => {}).constructor;
const fs = await new AsyncFunction('return import("node:fs"))');const fs = await import(new ModuleSource(`
export default new Function('return import("node:fs")')();
`));Closing every escape gadget requires rigor — but is possible!
There was a problem hiding this comment.
I'm not so sure about the undeniables. Might as well rely on their undeniability or on getIntrinsics.
When we discussed this, the idea to insert no opinions about the list of globals being available as a minimum was established and I thought that means with keys: [] the only globals that exist are Global and evaluator. Maybe no Global even.
There was a problem hiding this comment.
Earlier, we had this:
const source = new ModuleSource("export default {}");
(await thatGlobal.eval("(...args) => import(...args)")(source)) !==
(await import(source));
thatGlobal.ModuleSource === thisGlobal.ModuleSource;and now it's fs1 === fs2; // if present
I think that's a change in assumptions about ModuleSource instantiation and module map. When is module map not inherited? If an import hook is created?
Co-authored-by: Kris Kowal <kriskowal@kriskowal.com>
|
Two comment threads are still open, but I'll merge and offer the slides link in the agenda. |
No description provided.