"Stages" can be controlled by users via hooks and by calling .resolve() or .reject() on a ModuleStatus object. Stages are "fetch", "translate" and "instantiate".
"Phases" (or Evaluation Phases) are internals, and users can't affect or inspect them in any way. Phases are "satisfy", "link" and "ready".
"Satisfy" phase is triggered before resolving the "instantiate" stage, these is, for now, the last piece that is async in the pipeline, after that, linking and evaluation is sync, but that might change in the future with top level async calls.
Module.evaluate(ns) is now specced, and it is async to guarantee future proof.
readiness can only be achieve by invoking loader.import("name") or Module.evaluate(ns).
Other fixes
update Realm Record term to align with 262.
mutator getters will throw.
Invariants
the namespace of a source text module record can only be accessed in user-land after finishing SatisfyInstance() via await loader.import(), await Module.evaluate() or get entry.module.
the namespace of a dynamic module record is "satisfied" by definition (it can only be created via new Module()), which guarantees that all namespace exotic from module records in user-land are "satisfied".
new ModuleStatus(loader, key, ns) can be used to synchronously populate the registry because all namespace objects in user-land are "satisfied".
Rationale
The primary motivation is to enable synchronous registration of pre-instantiated modules. This is important for use cases like polyfills in the browser and for Node compatibility.
But we would need to be sure that such an API cannot add a not-fully-satisfied module. If we did, there would be no way for the ModuleStatus object in the registry to know where it stands in the loading pipeline. We'd have to keep back-pointers to module namespace objects' ModuleStatus objects in order to know when they are safe to be synchronously added. But there's a many-to-one relationship between ModuleStatus objects and module instances -- and it'd be nonsense to allow different ModuleStatuses to fight with each other about how to satisfy the dependencies of a module.
The way to make this coherent is to have an invariant that by the time a module instance is exposed to userland, all its dependencies have been satisfied. This keeps the roles and responsibilities of module namespace objects and ModuleStatus objects distinct, and ensures that synchronous registration is rational.
Features
.resolve()
or.reject()
on a ModuleStatus object. Stages are "fetch", "translate" and "instantiate".Module.evaluate(ns)
is now specced, and it is async to guarantee future proof.loader.import("name")
orModule.evaluate(ns)
.Other fixes
Invariants
SatisfyInstance()
viaawait loader.import()
,await Module.evaluate()
orget entry.module
.new Module()
), which guarantees that all namespace exotic from module records in user-land are "satisfied".new ModuleStatus(loader, key, ns)
can be used to synchronously populate the registry because all namespace objects in user-land are "satisfied".Rationale
The primary motivation is to enable synchronous registration of pre-instantiated modules. This is important for use cases like polyfills in the browser and for Node compatibility.
But we would need to be sure that such an API cannot add a not-fully-satisfied module. If we did, there would be no way for the ModuleStatus object in the registry to know where it stands in the loading pipeline. We'd have to keep back-pointers to module namespace objects' ModuleStatus objects in order to know when they are safe to be synchronously added. But there's a many-to-one relationship between ModuleStatus objects and module instances -- and it'd be nonsense to allow different ModuleStatuses to fight with each other about how to satisfy the dependencies of a module.
The way to make this coherent is to have an invariant that by the time a module instance is exposed to userland, all its dependencies have been satisfied. This keeps the roles and responsibilities of module namespace objects and ModuleStatus objects distinct, and ensures that synchronous registration is rational.
ASCII graph for this pipeline refactor