# Loader

## A Collection of Interesting Ideas — Last Updated 1 January 1970

Participate:
  GitHub whatwg/loader (new issue, open issues)
  IRC: #whatwg on Freenode
  File an issue (open issues)
Commits:
  GitHub whatwg/loader/commits
  [SNAPSHOT-LINK]
  @[TWITTER]
Tests:
  web-platform-tests loader/ (ongoing work)
This version:
  https://whatwg.github.io/loader
Editors:
  Eric Ferraiuolo (Yahoo) edf@ericf.me
  Dave Herman (Mozilla) dherman@mozilla.com
  Yehuda Katz (jQuery Foundation) wycats@gmail.com
  Caridy Patiño (Yahoo) caridy@gmail.com
Version History:
  https://github.com/whatwg/loader/commits

## Abstract

This specification describes the behavior of loading JavaScript modules from a JavaScript host environment. It also provides APIs for intercepting the module loading process and customizing loading behavior.

## Status

This document is a work in progress and dreams of becoming a living standard.

## 1. Module Loading

This section is non-normative.

### 1.1. Introduction

Throughout their development, JavaScript modules have been divided into two general areas:

- The authoring format, which defines the importing and exporting syntax, as well as the semantics for variable bindings and cycles.
- The JavaScript Loader, which provides a pipeline for on-demand, asynchronous loading of JavaScript modules.

The authoring format was carefully designed to support pre-compilation (like Browserify) and on-demand asynchronous loading (like AMD). It defines the minimal syntax necessary to allow people to write portable modules that can work across different platforms, most notably Node.js and web browsers.

The JavaScript Loader allows host environments, like Node.js and browsers, to fetch and load modules on demand. It provides a hookable pipeline, to allow front-end packaging solutions like Browserify, WebPack and jspm to hook into the loading process.

This division provides a single format that developers can use in all JavaScript environments, and a separate loading mechanism for each environment. For example, a Node Loader would load its modules from the file system, using its own module lookup algorithm, while a Browser Loader would fetch modules and use browser-supplied packaging formats.

JavaScript itself, in ECMAScript 2015, defines the module syntax and the "linking semantics" between modules. When a module is requested, it delegates responsibility for loading the module to the host environment. The Loader defines how host environments can allow JavaScript code to configure that process.

The primary goal is to make as much of this process as possible consistent between Node and Browser environments. For example, if a JavaScript program wants to translate `.coffee` files to JavaScript on the fly, the Loader defines a "translate" hook that can be used. This allows programs to participate in the loading process, even though some details (specifically, the process of getting a particular module from its host-defined storage) will be different between environments.

### 1.2. Loader Pipeline

TODO: include pipeline diagram

## 2. Conventions

### 2.1. Well-Known Symbols

Well-known symbols are built-in Symbol values that are explicitly referenced by algorithms of this specification. They are typically used as the keys of properties whose values serve as extension points of a specification algorithm.

Within this specification a well-known symbol is referred to by using a notation of the form @@name, where "name" is one of the values listed in table below:

Specification Name | [[Description]] | Value and Purpose
--- | --- | ---
@@resolve | "Reflect.Loader.resolve" | A function valued property that is the resolve hook function of loader’s instances.
@@fetch | "Reflect.Loader.fetch" | A function valued property that is the fetch hook function of loader’s instances.
@@translate | "Reflect.Loader.translate" | A function valued property that is the translate hook function of loader’s instances.
@@instantiate | "Reflect.Loader.instantiate" | A function valued property that is the instantiate hook function of loader’s instances.

### 2.2. Well-Known Intrinsic Objects

Well-known intrinsics are built-in objects that are explicitly referenced by the algorithms of this specification and which usually have realm-specific identities. Unless otherwise specified each intrinsic object actually corresponds to a set of similar objects, one per realm.

Within this specification a reference such as %name% means the intrinsic object, associated with the current realm, corresponding to the name. Determination of the current realm and its intrinsics is described in ES2015, 8.3.

### 2.3. Promises

This spec makes heavy use of promises, and adopts the notational conventions established in the promises guide.

#### 2.3.1. Reacting to Promises

Transforming p with a new pass-through promise is a shorthand for wrapping the promise to avoid exposing the original promise. It represents the following step:

1. Transforming _p_ with a fulfillment handler that, when called with argument _value_, returns _value_.

### 2.4. Shorthand Phrases

#### 2.4.1. RejectIfAbrupt(x)

Algorithm steps that say

1. RejectIfAbrupt(_x_).

mean the same thing as:

1. If _x_ is an abrupt completion, return a promise rejected with _x_.[[Value]]. 1. Else if _x_ is a Completion Record, then let _x_ be _x_.[[Value]].

### 2.5. Common Operations

#### 2.5.1. CreateObject()

1. Let _obj_ be ObjectCreate(%ObjectPrototype%). 1. Return _obj_.

#### 2.5.2. SimpleDefine(obj, name, value)

1. Let _desc_ be a new PropertyDescriptor record {[[Value]]: _value_, [[Writable]]: *true*, [[Enumerable]]: *true*, [[Configurable]]: *true*}. 1. Return ? OrdinaryDefineOwnProperty(_obj_, _name_, _desc_).

### 2.6. Built-in Function Objects

We follow the ECMA-262 convention for built-in function objects in which the value of NewTarget in each function argument is **undefined** for [[Call]] and the newTarget parameter for [[Construct]].

## 3. Loader Objects

### 3.1. The Loader Constructor

The Loader constructor is the %Loader% intrinsic object and the initial value of the Loader property of the Reflect object. When called as a constructor it creates and initializes a new Loader object. When Loader is called as a function rather than as a constructor, it throws an exception.

The Loader constructor is designed to be subclassable. It may be used as the value of an extends clause of a class definition. Subclass constructors that intend to inherit the specified Loader behaviour must include a super call to the Loader constructor to create and initialize the subclass instance with the corresponding internal slots.

#### 3.1.1. Loader()

When Loader is called with no arguments, the following steps are taken:

1. If NewTarget is *undefined*, then throw a *TypeError* exception. 1. Let _O_ be ? OrdinaryCreateFromConstructor(NewTarget, "%LoaderPrototype%", «[[Realm]], [[Registry]]»). 1. Set _O_’s [[Realm]] internal slot to current Realm Record. 1. Set _O_’s [[Registry]] internal slot to CreateRegistry(). 1. Return _O_.

### 3.2. Properties of the Loader Constructor

The value of the [[Prototype]] internal slot of the Loader constructor is the intrinsic object %FunctionPrototype%.

The Loader constructor has the following properties:

#### 3.2.1. Loader.prototype

The initial value of Loader.prototype is the intrinsic object %LoaderPrototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

### 3.3. Properties of the Loader Prototype Object

#### 3.3.1. Loader.prototype.constructor

The initial value of Loader.prototype.constructor is the intrinsic object %Loader%.

#### 3.3.2. Loader.prototype.import(name[, referrer])

The following steps are taken:

1. Let _loader_ be *this* value. 1. If Type(_loader_) is not Object, throw a *TypeError* exception. 1. If _loader_ does not have all of the internal slots of a Loader Instance (3.4), throw a *TypeError* exception. 1. Return the result of transforming Resolve(_loader_, _name_, _referrer_) with a fulfillment handler that, when called with argument _key_, runs the following steps: 1. Let _entry_ be EnsureRegistered(_loader_, _key_). 1. Return the result of transforming LoadModule(_entry_, "instantiate") with a fulfillment handler that, when called, runs the following steps: 1. Return EnsureEvaluated(_entry_).

#### 3.3.3. Loader.prototype.resolve(name[, referrer])

The following steps are taken:

1. Let _loader_ be *this* value. 1. If Type(_loader_) is not Object, throw a *TypeError* exception. 1. If _loader_ does not have all of the internal slots of a Loader Instance (3.4), throw a *TypeError* exception. 1. Return the result of transforming Resolve(_loader_, _name_, _referrer_) with a new pass-through promise.

#### 3.3.4. Loader.prototype.load(name[, referrer[, stage]])

The following steps are taken:

1. Let _loader_ be *this* value. 1. If Type(_loader_) is not Object, throw a *TypeError* exception. 1. If _loader_ does not have all of the internal slots of a Loader Instance (3.4), throw a *TypeError* exception. 1. If _stage_ is *undefined* then let _stageValue_ be "instantiate". 1. Else let _stageValue_ be ToString(_stage_). 1. RejectIfAbrupt(_stageValue_). 1. If IsValidStageValue(_stageValue_) is *false*, return a promise rejected with a new *RangeError* exception. 1. Return the result of transforming Resolve(_loader_, _name_, _referrer_) with a fulfillment handler that, when called with argument _key_, runs the following steps: 1. Let _entry_ be EnsureRegistered(_loader_, _key_). 1. Return LoadModule(_entry_, _stageValue_).

#### 3.3.5. get Loader.prototype.registry

`Loader.prototype.registry` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _loader_ be *this* value. 1. If Type(_loader_) is not Object, throw a *TypeError* exception. 1. If _loader_ does not have all of the internal slots of a Loader Instance (3.4), throw a *TypeError* exception. 1. Return _loader_.[[Registry]].

#### 3.3.6. Loader.prototype [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "Object".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

### 3.4. Properties of Loader Instances

Loader instances are ordinary objects that inherit properties from the *Loader.prototype*.

Loader instances are initially created with the internal slots described in the following table:

Internal Slot | Value Type (non-normative) | Description (non-normative)
--- | --- | ---
[[Realm]] | Realm Record | The realm this loader belongs to.
[[Registry]] | An object | An instance of Registry.

## 4. Registry Objects

### 4.1. Abstract Operations for Registry Objects

#### 4.1.1. CreateRegistry()

The abstract operation CreateRegistry with no arguments performs the following steps:

1. Let _O_ be ? OrdinaryCreateFromConstructor(Registry, "%RegistryPrototype%", «[[RegistryMap]]» ). 1. Let _M_ be ObjectCreate(%MapIteratorPrototype%, «[[Map]], [[MapNextIndex]], [[MapIterationKind]]»). 1. Set _O_’s [[RegistryMap]] internal slot to _M_. 1. Return _O_.

### 4.2. The Registry Constructor

The Registry constructor is the %Registry% intrinsic object. It is not intended to be called as a function or as a constructor and will always throw an exception.

### 4.3. Properties of the Registry Constructor

The value of the [[Prototype]] internal slot of the Registry constructor is the intrinsic object %FunctionPrototype%.

The Registry constructor has the following properties:

#### 4.3.1. Registry.prototype

The initial value of Registry.prototype is %RegistryPrototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

### 4.4. Properties of the Registry Prototype Object

#### 4.4.1. Registry.prototype.constructor

The initial value of the constructor property of the %RegistryPrototype% object is the %Registry% object.

Always throws to prevent the creation of new registry objects in user-land.

#### 4.4.2. Registry.prototype[ @@iterator ]()

The initial value of the @@iterator property is the same function object as the initial value of the entries property.

The value of the name property of this function is "[Symbol.iterator]".

#### 4.4.3. Registry.prototype.entries()

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Return CreateMapIterator(_M_, "key+value").

#### 4.4.4. Registry.prototype.keys()

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Return CreateMapIterator(_M_, "key").

#### 4.4.5. Registry.prototype.values()

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Return CreateMapIterator(_M_, "value").

#### 4.4.6. Registry.prototype.get(key)

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Let _entries_ be the List that is the value of _M_’s [[MapData]] internal slot. 1. Repeat for each Record {[[key]], [[value]]} _p_ that is an element of _entries_, 1. If _p_.[[key]] is not empty and SameValueZero(_p_.[[key]], _key_) is *true*, return _p_.[[value]]. 1. Return *undefined*.

#### 4.4.7. Registry.prototype.set(key, entry)

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Let _entries_ be the List that is the value of _M_’s [[MapData]] internal slot. 1. Repeat for each Record {[[key]], [[value]]} _p_ that is an element of _entries_, 1. If _p_.[[key]] is not empty and SameValueZero(_p_.[[key]], _key_) is *true*, then 1. Set _p_.[[value]] to _entry_. 1. Return _registry_. 1. Let _p_ be the Record {[[key]]: _key_, [[value]]: _entry_}. 1. Append _p_ as the last element of _entries_. 1. Return _registry_.

#### 4.4.8. Registry.prototype.has(key)

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Let _entries_ be the List that is the value of _M_’s [[MapData]] internal slot. 1. Repeat for each Record {[[key]], [[value]]} _p_ that is an element of _entries_, 1. If _p_.[[key]] is not empty and SameValueZero(_p_.[[key]], _key_) is *true*, then, return *true*. 1. Return *false*.

#### 4.4.9. Registry.prototype.delete(key)

The following steps are taken:

1. Let _registry_ be *this* value. 1. If Type(_registry_) is not Object, throw a *TypeError* exception. 1. If _registry_ does not have all of the internal slots of a Registry Instance (4.4), throw a *TypeError* exception. 1. Let _M_ be _registry_.[[RegistryMap]]. 1. Let _entries_ be the List that is the value of _M_’s [[MapData]] internal slot. 1. Repeat for each Record {[[key]], [[value]]} _p_ that is an element of _entries_, 1. If _p_.[[key]] is not empty and SameValueZero(_p_.[[key]], _key_) is *true*, then 1. Set _p_.[[key]] to empty. 1. Set _p_.[[value]] to empty. 1. Return *true*. 1. Return *false*. The value empty is used as a specification device to indicate that an entry has been deleted. Actual implementations may take other actions such as physically removing the entry from internal data structures.

### 4.5. Properties of Registry Instances

Registry instances are ordinary objects that inherit properties from the %RegistryPrototype%.

Registry instances are initially created with the internal slots described in the following table:

Internal Slot | Value Type (non-normative) | Description (non-normative)
--- | --- | ---
[[RegistryMap]] | The Map object of pairs of String and module status. | The registry of installed modules.

## 5. ModuleStatus Objects

### 5.1. Abstract Operations for ModuleStatus Objects

#### 5.1.1. GetCurrentStage(entry)

The abstract operation GetCurrentStage with argument entry performs the following steps:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _stages_ be _entry_.[[Pipeline]]. 1. Return the first element of _stages_.

#### 5.1.2. IsValidStageValue(stage)

The abstract operation IsValidStageValue with argument stage performs the following steps:

1. Assert: Type(_stage_) is String. 1. If _stage_ is "fetch", "translate" or "instantiate", return *true*. 1. Else return *false*.

#### 5.1.3. GetStage(entry, stage)

The abstract operation GetStage with arguments entry and stage performs the following steps:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Assert: Type(_stage_) is String. 1. Let _stages_ be _entry_.[[Pipeline]]. 1. For each element _stageEntry_ of _stages_, do 1. If _stageEntry_.[[Stage]] is equal to _stage_, return _stageEntry_. 1. Return *undefined*.

#### 5.1.4. LoadModule(entry, stage)

The abstract operation LoadModule with arguments entry and stage performs the following steps:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Assert: Type(_stage_) is String. 1. Assert: _stage_ is a valid stage value. 1. If _stage_ is "fetch", then: 1. Return the result of transforming RequestFetch(_entry_) with a new pass-through promise. 1. If _stage_ is "translate", then: 1. Return the result of transforming RequestTranslate(_entry_) with a new pass-through promise. 1. If _stage_ is "instantiate", then: 1. Return the result of transforming RequestInstantiate(_entry_) with a new pass-through promise. 1. Return a promise rejected with a new *RangeError* exception.

#### 5.1.5. UpgradeToStage(entry, stage)

The abstract operation UpgradeToStage with arguments entry and stage performs the following steps:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Assert: Type(_stage_) is String. 1. Let _pipeline_ be _entry_.[[Pipeline]]. 1. Let _stageEntry_ be GetStage(_entry_, _stage_). 1. If _stageEntry_ is not *undefined*, then 1. Repeat while the first element of _pipeline_ is not equal to _stageEntry_ 1. Remove first element from _pipeline_. The internal slot [[Pipeline]] of an entry can never be empty. Alternative, this algo can be implemented using functional programming techniques or a reverse cycle to avoid walking the entries twice.

A stage is a record with the following fields:

Internal Slot | Value Type (non-normative) | Description (non-normative)
--- | --- | ---
[[Stage]] | `"fetch"`, `"translate"`, `"instantiate"` | A constant value to indicating which phase the entry is at.
[[Result]] | Promise or `undefined` | A promise for the stage entry.

Each [[Stage]] value indicates the currently pending operation. If the [[Result]] field is *undefined*, the operation has not been initiated; if the [[Result]] field is a promise, the operation has been initiated but not completed. Once a stage completes, its Stage Entry is removed from the pipeline. The following table describes the intended purpose of each stage of the pipeline:

Value | Description (non-normative)
--- | ---
`"fetch"` | fetching the requested module (e.g. from a filesystem or network)
`"translate"` | translating the fetched source (as via a preprocessor or compiler)
`"instantiate"` | instantiating the translated source as a Module Record

### 5.2. The ModuleStatus Constructor

The ModuleStatus constructor is the %ModuleStatus% intrinsic object and the initial value of the Status property of the Reflect.Module object. When called as a constructor it creates and initializes a new ModuleStatus object. When ModuleStatus is called as a function rather than as a constructor, it throws an exception.

The ModuleStatus constructor is designed to be subclassable. It may be used as the value of an extends clause of a class definition. Subclass constructors that intend to inherit the specified ModuleStatus behaviour must include a super call to the ModuleStatus constructor to create and initialize the subclass instance with the corresponding internal slots.

#### 5.2.1. ModuleStatus(loader, key, ns)

When ModuleStatus is called with arguments loader, key and ns, the following steps are taken:

1. If NewTarget is *undefined*, then throw a *TypeError* exception. 1. If Type(_loader_) is not Object, throw a *TypeError* exception. 1. If _loader_ does not have all of the internal slots of a Loader Instance (3.4), throw a *TypeError* exception. 1. Let _keyString_ be ? ToString(_key_). 1. Let _O_ be ? OrdinaryCreateFromConstructor(NewTarget, "%ModuleStatusPrototype%", «[[Loader]], [[Pipeline]], [[Key]], [[Module]], [[Metadata]], [[Dependencies]], [[Error]]» ). 1. Let _pipeline_ be a new List. 1. If _ns_ is *undefined*, then: 1. Let _module_ be *undefined*. 1. Let _deps_ be *undefined*. 1. Add new stage entry record { [[Stage]]: "fetch", [[Result]]: *undefined* } as a new element of the list _pipeline_. 1. Add new stage entry record { [[Stage]]: "translate", [[Result]]: *undefined* } as a new element of the list _pipeline_. 1. Add new stage entry record { [[Stage]]: "instantiate", [[Result]]: *undefined* } as a new element of the list _pipeline_. 1. Else, 1. If _ns_ is not a module namespace exotic object, throw a *TypeError* exception. 1. Let _module_ be _ns_.[[Module]]. 1. Let _deps_ be a new empty List. 1. Assert: _module_ is a Module Record. 1. Assert: All [[RequestedModule]] of _module_ are safistied. 1. Let _result_ be a promise resolved with _ns_. 1. Add new stage entry record { [[Stage]]: "instantiate", [[Result]]: _result_ } as a new element of the list _pipeline_. 1. Set _O_’s [[Loader]] internal slot to _loader_. 1. Set _O_’s [[Pipeline]] internal slot to _pipeline_. 1. Set _O_’s [[Key]] internal slot to _keyString_. 1. Set _O_’s [[Module]] internal slot to _module_. 1. Set _O_’s [[Metadata]] internal slot to *undefined*. 1. Set _O_’s [[Dependencies]] internal slot to _deps_. 1. Set _O_’s [[Error]] internal slot to *false*. 1. Return _O_. A module status is associated to a loader instance at the time of its creation, the [[Loader]] backpointer reflects that. The optional third argument ns allows to create a module status in a way that synchronously circumvents the asynchronous loading process. A module status can be set into multiple Registry instances.

### 5.3. Properties of the ModuleStatus Constructor

The value of the [[Prototype]] internal slot of the Registry constructor is the intrinsic object %FunctionPrototype%.

The ModuleStatus constructor has the following properties:

#### 5.3.1. ModuleStatus.prototype

The initial value of ModuleStatus.prototype is the intrinsic object %ModuleStatusPrototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

### 5.4. Properties of the ModuleStatus Prototype Object

#### 5.4.1. ModuleStatus.prototype.constructor

The initial value of ModuleStatus.prototype.constructor is the intrinsic object %ModuleStatus%.

#### 5.4.2. get ModuleStatus.prototype.stage

`ModuleStatus.prototype.stage` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Let _stageEntry_ be GetCurrentStage(_entry_). 1. Return _stageEntry_.[[Stage]].

#### 5.4.3. get ModuleStatus.prototype.originalKey

`ModuleStatus.prototype.originalKey` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Return _entry_.[[Key]].

#### 5.4.4. get ModuleStatus.prototype.module

`ModuleStatus.prototype.module` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Let _module_ be _entry_.[[Module]]. 1. If _module_ is a Module Record, return GetModuleNamespace(_module_). 1. Return *undefined*.

#### 5.4.5. get ModuleStatus.prototype.error

`ModuleStatus.prototype.error` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Return _entry_.[[Error]].

#### 5.4.6. get ModuleStatus.prototype.dependencies

`ModuleStatus.prototype.dependencies` is an accessor property whose set accessor function is undefined. Its get accessor function performs the following steps:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, throw a *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), throw a *TypeError* exception. 1. Let _array_ be ArrayCreate(0). 1. Let _n_ be 0. 1. For each _pair_ in _entry_.[[Dependencies]], do: 1. Let _O_ be ObjectCreate(%ObjectPrototype%). 1. Let _requestNameDesc_ be the PropertyDescriptor{[[Value]]: _pair_.[[RequestName]], [[Writable]]: *false*, [[Enumerable]]: *true*, [[Configurable]]: *false*}. 1. Perform ? DefinePropertyOrThrow(_O_, "requestName", _requestNameDesc_). 1. Let _moduleStatusDesc_ be the PropertyDescriptor{[[Value]]: _pair_.[[ModuleStatus]], [[Writable]]: *false*, [[Enumerable]]: *true*, [[Configurable]]: *false*}. 1. Perform ? DefinePropertyOrThrow(_O_, "entry", _moduleStatusDesc_). 1. Perform ? CreateDataProperty(_array_, ? ToString(_n_), _O_). 1. Increment _n_ by 1. 1. Return _array_. The dependencies accessor provides access to the dependency graph, exposing each dependency’s requestName, key and entry reference.

#### 5.4.7. ModuleStatus.prototype.load(stage)

The following steps are taken:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, return a promise rejected with a new *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), return a promise rejected with a new *TypeError* exception. 1. If _stage_ is *undefined*, let _stageValue_ be "fetch"; otherwise, let _stageValue_ be ToString(_stage_). 1. RejectIfAbrupt(_stageValue_). 1. If IsValidStageValue(_stageValue_) is *false*, return a promise rejected with a new *RangeError* exception. 1. Return LoadModule(_entry_, _stageValue_).

#### 5.4.8. ModuleStatus.prototype.result(stage)

The following steps are taken:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, return a promise rejected with a new *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), return a promise rejected with a new *TypeError* exception. 1. Let _stageValue_ be ToString(_stage_). 1. RejectIfAbrupt(_stageValue_). 1. If IsValidStageValue(_stageValue_) is *false*, return a promise rejected with a new *RangeError* exception. 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. If _stageEntry_ is *undefined*, return a promise resolved with *undefined*. 1. If _stageEntry_.[[Result]] is *undefined*, return a promise resolved with *undefined*. 1. Return the result of transforming _stageEntry_.[[Result]] with a new pass-through promise.

#### 5.4.9. ModuleStatus.prototype.resolve(stage, result)

The following steps are taken:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, return a promise rejected with a new *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), return a promise rejected with a new *TypeError* exception. 1. Let _stageValue_ be ToString(_stage_). 1. RejectIfAbrupt(_stageValue_). 1. If IsValidStageValue(_stageValue_) is *false*, return a promise rejected with a new *RangeError* exception. 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. If _stageEntry_ is *undefined*, return a promise rejected with a new *TypeError* exception. 1. Perform UpgradeToStage(_entry_, _stageValue_). 1. Let _p0_ be the result of transforming _result_ with a new pass-through promise. 1. Let _p1_ be the result of transforming _p0_ with a fulfillment handler that, when called with argument _value_, runs the following steps: 1. If _stageValue_ is "instantiate", then: 1. Return the result of transforming SatisfyInstance(_entry_, _value_, *undefined*, *undefined*) with a fulfillment handler that, when called with value _instance_, runs the following steps: 1. Set _entry_.[[Module]] to _instance_. 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. Assert: _stageEntry_ is not *undefined*. 1. Fulfill _stageEntry_.[[Result]] with _value_. 1. Else, 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. If _stageEntry_ is *undefined*, throw a new *TypeError*. 1. Fulfill _stageEntry_.[[Result]] with _value_. 1. Let _pCatch_ be the result of transforming _p1_ with a rejection handler that, when called, runs the following steps: 1. Set _entry_.[[Error]] to *true*. 1. If _stageEntry_.[[Result]] is *undefined*, set _stageEntry_.[[Result]] to _p1_. 1. Return _p1_.

#### 5.4.10. ModuleStatus.prototype.reject(stage, error)

The following steps are taken:

1. Let _entry_ be *this* value. 1. If Type(_entry_) is not Object, return a promise rejected with a new *TypeError* exception. 1. If _entry_ does not have all of the internal slots of a ModuleStatus Instance (5.5), return a promise rejected with a new *TypeError* exception. 1. Let _stageValue_ be ToString(_stage_). 1. RejectIfAbrupt(_stageValue_). 1. If IsValidStageValue(_stageValue_) is *false*, return a promise rejected with a new *RangeError* exception. 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. If _stageEntry_ is *undefined*, return a promise rejected with a new *TypeError* exception. 1. Perform UpgradeToStage(_entry_, _stageValue_). 1. Let _p0_ be the result of transforming _error_ with a new pass-through promise. 1. Let _p1_ be the result of transforming _p0_ with a fulfillment handler that, when called with argument _value_, runs the following steps: 1. Let _stageEntry_ be GetStage(_entry_, _stageValue_). 1. If _stageEntry_ is *undefined*, throw a new *TypeError*. 1. Reject _stageEntry_.[[Result]] with _value_. 1. Let _pCatch_ be the result of transforming _p1_ with a rejection handler that, when called, runs the following steps: 1. Set _entry_.[[Error]] to *true*. 1. If _stageEntry_.[[Result]] is *undefined*, set _stageEntry_.[[Result]] to _p1_. 1. Return _p1_.

### 5.5. Properties of ModuleStatus Instances

ModuleStatus instances are ordinary objects that inherit properties from the %ModuleStatusPrototype%.

ModuleStatus instances are initially created with the internal slots described in the following table:

Internal Slot | Value Type (non-normative) | Description (non-normative)
--- | --- | ---
[[Loader]] | An object | The loader this module status belongs to.
[[Pipeline]] | A List | A list whose elements are stage records.
[[Key]] | A String | A value that identifies what key was used to create the module status instance.
[[Metadata]] | Object or `undefined` | The metadata object passed through the pipeline.
[[Dependencies]] | List of Records of the form {[[RequestName]]: String, [[ModuleStatus]]: Module Status} . | Table mapping unresolved names to their resolved key and module status entries.
[[Module]] | Module Record or Function object or `undefined` | The Module Record or a thunk after the module has been satisfied; otherwise `undefined`.
[[Error]] | A Boolean | A boolean valued that if true indicates that an error that was encountered during one of the phases of the loading pipeline; false if no error has been encountered.

## 6. Loading Semantics

### 6.1. Auxiliary Operations

#### 6.1.1. EnsureRegistered(loader, key)

When the abstract operation EnsureRegistered is called with arguments loader and key, the following steps are taken:

1. Assert: _loader_ must have all of the internal slots of a Loader Instance (3.4). 1. Assert: Type(_key_) is String. 1. Let _registry_ be _loader_.[[Registry]]. 1. Let _M_ be registry.[[RegistryMap]]. 1. Let _entries_ be the List that is the value of _M_’s [[MapData]] internal slot. 1. Let _pair_ be the entry in _entries_ such that _pair_.[[key]] is equal to _key_. 1. If _pair_ exists, then: 1. Let _entry_ be _pair_.[[value]]. 1. Else, 1. Let _entry_ be a new ModuleStatus(_loader_, _key_). 1. Let _p_ be the Record {[[key]]: key, [[value]]: entry}. 1. Append _p_ as the last element of _entries_. 1. Return _entry_.

#### 6.1.2. Resolve(loader, name, referrer)

When the abstract operation Resolve is called with arguments loader, name and referrer, the following steps are taken:

1. Assert: _loader_ must have all of the internal slots of a Loader Instance (3.4). 1. Assert: Type(_name_) is String. 1. Assert: Type(_referrer_) is String. 1. Let _hook_ be GetMethod(_loader_, @@resolve). 1. Return the result of promise-calling _hook_(_name_, _referrer_).

#### 6.1.3. ExtractDependencies(entry, instance)

When the abstract operation ExtractDependencies is called with arguments entry and instance, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _deps_ be a new empty List. 1. If _instance_ is a Source Text Module Record, then: 1. For each _dep_ in _instance_.[[RequestedModules]], do: 1. Append the record { [[RequestName]]: _dep_, [[ModuleStatus]]: *undefined* } to _deps_. 1. Set _entry_.[[Dependencies]] to _deps_. [[Key]] will identify the dependency module status in the entry’s corresponding loader.

#### 6.1.4. Instantiation(loader, optionalInstance, source)

When the abstract operation Instantiation is called with arguments loader, optionalInstance and source, the following steps are taken:

1. Assert: _loader_ must have all of the internal slots of a Loader Instance (3.4). 1. If _optionalInstance_ is *undefined*, then: 1. If _source_ is not a ECMAScript source text, throw new *TypeError*. 1. Let _realm_ be _loader_.[[Realm]]. 1. Return ? ParseModule(_source_, _realm_, *undefined*). 1. If _optionalInstance_ is a namespace exotic object, return _optionalInstance_.[[Module]]. 1. If IsCallable(_optionalInstance_) is *false* then throw a new *TypeError*. 1. Return _optionalInstance_.

### 6.2. Loading Operations

#### 6.2.1. RequestFetch(entry)

When the abstract operation RequestFetch is called with argument entry, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _fetchStageEntry_ be GetStage(_entry_, "fetch"). 1. If _fetchStageEntry_ is *undefined*, return a promise resolved with *undefined*. 1. If _fetchStageEntry_.[[Result]] is not *undefined*, return _fetchStageEntry_.[[Result]]. 1. Let _hook_ be GetMethod(_entry_.[[Loader]], @@fetch). 1. Let _hookResult_ be the result of promise-calling _hook_(_entry_, _entry_.[[Key]]). 1. Let _p_ be the result of transforming _hookResult_ with a fulfillment handler that, when called with argument _payload_, runs the following steps: 1. Perform UpgradeToStage(_entry_, "translate"). 1. Return _payload_. 1. Let _pCatch_ be the result of transforming _p_ with a rejection handler that, when called, runs the following steps: 1. Set _entry_.[[Error]] to *true*. 1. Set _fetchStageEntry_.[[Result]] to _p_. 1. Return _p_.

#### 6.2.2. RequestTranslate(entry)

When the abstract operation RequestTranslate is called with argument entry, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _translateStageEntry_ be GetStage(_entry_, "translate"). 1. If _translateStageEntry_ is *undefined*, return a promise resolved with *undefined*. 1. If _translateStageEntry_.[[Result]] is not *undefined*, return _translateStageEntry_.[[Result]]. 1. Let _p_ be the result of transforming RequestFetch(_entry_) with a fulfillment handler that, when called with argument _payload_, runs the following steps: 1. Let _hook_ be GetMethod(_entry_.[[Loader]], @@translate). 1. Let _hookResult_ be the result of promise-calling _hook_(_entry_, _payload_). 1. Return the result of transforming _hookResult_ with a fulfillment handler that, when called with argument _source_, runs the following steps: 1. Perform UpgradeToStage(_entry_, "instantiate"). 1. Return _source_. 1. Let _pCatch_ be the result of transforming _p_ with a rejection handler that, when called, runs the following steps: 1. Set _entry_.[[Error]] to *true*. 1. Set _translateStageEntry_.[[Result]] to _p_. 1. Return _p_.

#### 6.2.3. RequestInstantiate(entry, instantiateSet)

When the abstract operation RequestInstantiate is called with arguments entry and instantiateSet, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _instantiateStageEntry_ be GetStage(_entry_, "instantiate"). 1. If _instantiateStageEntry_ is *undefined*, return a promise resolved with *undefined*. 1. If _instantiateStageEntry_.[[Result]] is not *undefined*, return _instantiateStageEntry_.[[Result]]. 1. Let _p_ be the result of transforming RequestTranslate(_entry_) with a fulfillment handler that, when called with argument _source_, runs the following steps: 1. Let _hook_ be GetMethod(_entry_.[[Loader]], @@instantiate). 1. Let _hookResult_ be the result of promise-calling _hook_(_entry_, _source_). 1. Return the result of transforming _hookResult_ with a fulfillment handler that, when called with argument _optionalInstance_, runs the following steps: 1. Return the result of transforming SatisfyInstance(_entry_, _optionalInstance_, _source_, _instantiateSet_) with a fulfillment handler that, when called with value _instance_, runs the following steps: 1. Set _entry_.[[Module]] to _instance_. 1. Return _optionalInstance_. 1. Let _pCatch_ be the result of transforming _p_ with a rejection handler that, when called, runs the following steps: 1. Set _entry_.[[Error]] to *true*. 1. Set _instantiateStageEntry_.[[Result]] to _p_. 1. Return _p_.

#### 6.2.4. SatisfyInstance(entry, optionalInstance, source, instantiateSet)

When the abstract operation SatisfyInstance is called with arguments entry, optionalInstance, source and instantiateSet, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. If _instantiateSet_ is *undefined*, Set _instantiateSet_ to a new empty List. 1. If _entry_ is already in _instantiateSet_, return *undefined*. 1. Append _entry_ to _instantiateSet_. 1. Let _loader_ be _entry_.[[Loader]]. 1. Let _instance_ be ? Instantiation(_loader_, _optionalInstance_, _source_). 1. If _instance_ is a Module Record, then: 1. Set _instance_.[[ModuleStatus]] to _entry_. 1. Perform ? ExtractDependencies(_entry_, _instance_). 1. Let _list_ be a new empty List. 1. For each _pair_ in _entry_.[[Dependencies]], do: 1. Let _p_ be the result of transforming Resolve(_loader_, _pair_.[[RequestName]], _entry_.[[Key]]) with a fulfillment handler that, when called with value _depKey_, runs the following steps: 1. Let _depEntry_ be EnsureRegistered(_loader_, _depKey_). 1. If _depEntry_ is already in _instantiateSet_, return *undefined*. 1. Set _pair_.[[ModuleStatus]] to _depEntry_. 1. Return RequestInstantiate(_depEntry_, _instantiateSet_). 1. Append _p_ to _list_. 1. Return the result of waiting for all _list_ with a fulfillment handler that, when called, return _instance_. This abstract operation guarantees that all [[Dependencies]] are instantiated and ready to be linked and evaluated.

## 7. Linking Semantics

### 7.1. Resolving Dependencies

#### 7.1.1. HostResolveImportedModule(module, requestName)

The modules spec should only invoke this abstract operation from methods of Source Text Module Records, and this spec does not invoke the operation at all.

When the abstract operation HostResolveImportedModule is called with arguments module and requestName, the following steps are taken:

1. Assert: _module_ is a Source Text Module Record. 1. Assert: Type(_requestName_) is String. 1. Let _entry_ be _module_.[[ModuleStatus]]. 1. Let _currentStageEntry_ be GetCurrentStage(_entry_). 1. Assert: _currentStageEntry_.[[Stage]] is "instantiate" and _currentStageEntry_.[[Result]] is a resolved promise. 1. Let _pair_ be the pair in _entry_.[[Dependencies]] such that _pair_.[[RequestName]] is equal to _requestName_. 1. Assert: _pair_ is defined. 1. Let _depEntry_ be _pair_.[[ModuleStatus]]. 1. Let _depStageEntry_ be GetCurrentStage(_depEntry_). 1. Assert: _depStageEntry_.[[Stage]] is "instantiate" and _depStageEntry_.[[Result]] is a resolved promise. 1. Return _depEntry_.[[Module]].

### 7.2. Linking

#### 7.2.1. DependencyGraph(root)

When the abstract operation DependencyGraph is called with argument root, the following steps are taken:

1. Assert: _root_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _result_ be a new empty List. 1. Call ComputeDependencyGraph(_root_, _result_). 1. Return _result_.

#### 7.2.2. ComputeDependencyGraph(entry, result)

When the abstract operation ComputeDependencyGraph is called with arguments entry and result, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Assert: _result_ must be a List. 1. If _entry_ is already in _result_, return *undefined*. 1. Insert _entry_ as the first element of _result_. 1. For each _pair_ in _entry_.[[Dependencies]], do: 1. Assert: _pair_.[[ModuleStatus]] is defined. 1. Call ComputeDependencyGraph(_pair_.[[ModuleStatus]], _result_). 1. Return *undefined*.

#### 7.2.3. EnsureLinked(entry)

When the abstract operation EnsureLinked is called with argument entry, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _deps_ be DependencyGraph(_entry_). 1. For each _dep_ in _deps_, do: 1. Let _depStageEntry_ be GetCurrentStage(_dep_). 1. Assert: _depStageEntry_.[[Stage]] is "instantiate" and _depStageEntry_.[[Result]] is a resolved promise. 1. If _dep_.[[Module]] is a Function object, then: 1. Let _func_ be _dep_.[[Module]]. 1. Let _argList_ be a new empty List. 1. Let _ns_ be ? Call(_func_, *undefined*, _argList_). 1. If _ns_ is not a module namespace exotic object, throw a *TypeError* exception. 1. Set _dep_.[[Module]] to _ns_.[[Module]]. 1. Assert: the following sequence is guaranteed not to run any user code. 1. For each _dep_ in _deps_, do: 1. Let _module_ be _dep_.[[Module]]. 1. Assert: _module_ is a Module Record. 1. Perform ? _module_.ModuleDeclarationInstantiation().

#### 7.2.4. EnsureEvaluated(entry)

When the abstract operation EnsureEvaluated is called with argument entry, the following steps are taken:

1. Assert: _entry_ must have all of the internal slots of a ModuleStatus Instance (5.5). 1. Let _stageEntry_ be GetCurrentStage(_entry_). 1. Assert: _stageEntry_.[[Stage]] is "instantiate" and _stageEntry_.[[Result]] is a resolved promise. 1. Let _module_ be _entry_.[[Module]]. 1. If _module_.[[Evaluated]] is *false*, then: 1. Perform ? EnsureLinked(entry). 1. Perform ? _module_.ModuleEvaluation(). 1. Return ? GetModuleNamespace(_module_).

## 8. Module Objects

### 8.1. Reflective Module Records

A reflective module record is a kind of module record. In addition to the fields defined in ES2016 Table 37, Reflective Module Records have the additional fields listed below. Each of these fields initially has the value undefined.

Internal Slot | Value Type (non-normative) | Description (non-normative)
--- | --- | ---
[[LocalExports]] | A List of Strings | The set of exported names stored in this module’s environment.
[[IndirectExports]] | A List of pairs of String and {[[module]]: Module Record, [[bindingName]]: String}. | The set of re-exported bindings. This ensures that ResolveExport can fully resolve re-exports.
[[Evaluate]] | A function object or `undefined` | A thunk to call when the module is evaluated, or `undefined` if the module is already evaluated.

-

### 8.2. Abstract Operations for Module Objects

#### 8.2.1. ParseExportsDescriptors(obj)

When the abstract operation ParseExportsDescriptors is called with argument obj, the following steps are taken:

1. Assert: Type(_obj_) is an Object. 1. Let _props_ be ? ToObject(Obj). 1. Let _keys_ be ? _props_.[[OwnPropertyKeys]](). 1. Let _descriptors_ be an empty List. 1. Repeat for each element _nextKey_ of _keys_ in List order, 1. Let _propDesc_ be ? props.[[GetOwnProperty]](_nextKey_). 1. If _propDesc_ is not *undefined* and _propDesc_.[[Enumerable]] is *true*, then 1. Let _descObj_ be ? Get(_props_, _nextKey_). 1. Let _hasModule_ be ? HasProperty(_descObj_, "module"). 1. If _hasModule_ is *true*, then 1. Let _ns_ be ? Get(_descObj_, "module"). 1. If _ns_ is not a module namespace exotic object, throw a *TypeError* exception. 1. Let _import_ be ToString(? Get(_descObj_, "import")). 1. Let _desc_ be a new Indirect Export Descriptor Record {[[Name]]: _nextKey_, [[Module]]: _ns_.[[Module]], [[Import]]: _import_}. 1. Else, 1. Let _hasValue_ be ? HasProperty(_descObj_, "value"). 1. If _hasValue_ is *true*, let _value_ be ? Get(_descObj_, "value"). 1. Let _hasConst_ be ? HasProperty(_descObj_, "const"). 1. If _hasConst_ is *true*, let _isConst_ be ToBoolean(? Get(_descObj_, "const")). 1. If _isConst_ is *true*, then 1. If _hasValue_ is *true*, then 1. Let _desc_ be a new Immutable Export Descriptor Record {[[Name]]: _nextKey_, [[Value]]: _value_, [[Initialized]]: *true*}. 1. Else, 1. Let _desc_ be a new Immutable Export Descriptor Record {[[Name]]: _nextKey_, [[Value]]: *undefined*, [[Initialized]]: *false*}. 1. Else, 1. If _hasValue_ is *true*, then 1. Let _desc_ be a new Mutable Export Descriptor Record {[[Name]]: _nextKey_, [[Value]]: _value_, [[Initialized]]: *true*}. 1. Else, 1. Let _desc_ be a new Mutable Export Descriptor Record {[[Name]]: _nextKey_, [[Value]]: *undefined*, [[Initialized]]: *false*}. 1. Append _desc_ to the end of _descriptors_. 1. Return _descriptors_. Parse as in these examples

- uninitialized, mutable: `{ }`
- uninitialized, immutable: `{ const: true }`
- initialized, mutable: `{ value: 42 }`
- initialized, immutable: `{ value: 42, const: true }`
- re-export (immutable): `{ module: m, import: "foo" }`

#### 8.2.2. CreateModuleMutator(module)

When the abstract operation CreateModuleMutator is called with argument module, the following steps are taken:

1. Assert: _module_ is a Reflective Module Records. 1. Let _mutator_ be ObjectCreate(%ObjectPrototype%). 1. Let _env_ be _module_.[[Environment]]. 1. Let _envRec_ be env’s environment record. 1. For each _name_ in _module_.[[LocalExports]], do: 1. Assert: _mutator_ does not already have a binding for _name_. 1. Let _p_ be MakeArgSetter(_name_, _envRec_). 1. Let _localExportDesc_ be the PropertyDescriptor{[[Get]]: %ThrowTypeError%, [[Set]]: _p_, [[Enumerable]]: true, [[Configurable]]: false}. 1. Perform ? DefinePropertyOrThrow(_mutator_, _name_, _localExportDesc_). 1. Return _mutator_.

#### 8.2.3. GetExportNames(exportStarStack)

When the abstract operation GetExportNames is called with argument exportStarStack, the following steps are taken:

1. Let _module_ be this Reflective Module Record. 1. Let _exports_ be a new empty List. 1. For each _name_ in _module_.[[LocalExports]], do: 1. Append _name_ to _exports_. 1. For each _pair_ in _module_.[[IndirectExports]], do: 1. Append _pair_.[[Key]] to _exports_. 1. Return _exports_.

#### 8.2.4. ResolveExport(exportName, resolveStack, exportStarStack)

When the abstract operation ResolveExport is called with arguments exportName, resolveStack and exportStarStack, the following steps are taken:

1. Let _module_ be this Reflective Module Record. 1. If _resolveStack_ contains a record _r_ such that _r_.[[module]] is equal to _module_ and _r_.[[exportName]] is equal to _exportName_, then 1. Assert: this is a circular import request. 1. Throw a *SyntaxError* exception. 1. Append the record {[[module]]: _module_, [[exportName]]: _exportName_} to _resolveStack_. 1. Let _localExports_ be _module_.[[LocalExports]]. 1. If _exportName_ is in _localExports_, then: 1. Return the Record { [[module]]: _module_, [[bindingName]]: _exportName_ }. 1. Let _indirectExports_ be _module_.[[IndirectExports]]. 1. Let _pair_ be the pair in _indirectExports_ such that _pair_.[[Key]] is equal to _exportName_. 1. If _pair_ is defined, return _pair_.[[Value]]. 1. Return *null*.

#### 8.2.5. ModuleDeclarationInstantiation()

When the abstract operation ModuleDeclarationInstantiation is called with no arguments, the following steps are taken:

1. Return *undefined*. Reflective modules are always already instantiated.

#### 8.2.6. ModuleEvaluation()

When the abstract operation ModuleEvaluation is called with no arguments, the following steps are taken:

1. Let _module_ be this Reflective Module Record. 1. If _module_.[[Evaluated]] is *true*, return *undefined*. 1. Let _func_ be _module_.[[Evaluate]]. 1. Set _module_.[[Evaluated]] to *true*. 1. Set _module_.[[Evaluate]] to *undefined*. 1. For each _pair_ in _module_.[[IndirectExports]], do: 1. Let _requiredModule_ be _pair_.[[Value]].[[module]]. 1. Assert: _requiredModule_ is a Module Record. 1. Perform ? _requiredModule_.ModuleEvaluation(). 1. If IsCallable(_func_) is *true*, then: 1. Let _argList_ be a new empty List. 1. Perform ? Call(func, *undefined*, argList). 1. Return *undefined*.

### 8.3. The Module Constructor

The Module constructor is the initial value of the Module property of the Reflect object. When called as a constructor it creates and initializes a new Module object. Module is not intended to be called as a function and will throw an exception when called in that manner.

The Module constructor is designed to be subclassable. It may be used as the value in an extends clause of a class definition. Subclass constructors that intend to inherit the specified Module behaviour must include a super call to the Module constructor to create and initialize the subclass instance with the internal stage necessary to integrate with loaders.

#### 8.3.1. Module(descriptors[, executor[, evaluate]])

When Module is called with arguments descriptors, executor, and evaluate, the following steps are taken:

1. Let _realm_ be the current Realm Record. 1. Let _env_ be NewModuleEnvironment(_realm_.[[globalEnv]]). 1. If Type(_descriptors_) is not Object, throw a *TypeError* exception. 1. Let _exportDescriptors_ be ParseExportsDescriptors(_descriptors_). // TODO: interleave the subsequent loop with parsing? 1. Let _localExports_ be a new empty List. 1. Let _indirectExports_ be a new empty List. 1. Let _exportNames_ be a new empty List. 1. Let _envRec_ be _env_’s environment record. 1. For each _desc_ in _exportDescriptors_, do: 1. Let _exportName_ be _desc_.[[Name]]. 1. Append _exportName_ to _exportNames_. 1. If _desc_ is an Indirect Export Descriptor, then: 1. Let _otherMod_ be _desc_.[[Module]]. 1. Let _resolution_ be ? _otherMod_.ResolveExport(_desc_.[[Import]], « »). 1. If _resolution_ is *null*, then throw a *SyntaxError* exception. 1. Append the record {[[Key]]: _exportName_, [[Value]]: _resolution_} to _indirectExports_. 1. Else, 1. Append _exportName_ to _localExports_. 1. If _desc_ is an Immutable Export Descriptor, then: 1. Perform ? _envRec_.CreateImmutableBinding(_exportName_, *true*). 1. Else, 1. Assert: _desc_ is a Mutable Export Descriptor. 1. Perform ? _envRec_.CreateMutableBinding(_exportName_, *false*). 1. If _desc_.[[Initialized]] is *true*, then: 1. Call _envRec_.InitializeBinding(_exportName_, _desc_.[[Value]]). 1. If _evaluate_ is not *undefined*, then 1. If IsCallable(_evaluate_) is *false*, throw a new *TypeError* exception. 1. Let _mod_ be a new Reflective Module Record {[[Realm]]: _realm_, [[Environment]]: _env_, [[Namespace]]: *undefined*, [[LocalExports]]: _localExports_, [[IndirectExports]]: _indirectExports_, [[Evaluated]]: *false*, [[Evaluate]]: _evaluate_, [[HostDefined]]: *undefined*}. 1. Let _ns_ be ModuleNamespaceCreate(_mod_, _exportNames_). 1. If _executor_ is not *undefined*, then 1. If IsCallable(_executor_) is *false*, throw a new *TypeError* exception. 1. Let _mutator_ be CreateModuleMutator(_mod_). 1. Perform ? _executor_(_mutator_, _ns_). 1. Return _ns_.

### 8.4. Properties of the Module Constructor

The value of the [[Prototype]] internal slot of the Module constructor is the intrinsic object %FunctionPrototype%.

The Loader constructor has the following properties:

#### 8.4.1. Module.evaluate(ns)

When Module.evaluate is called with argument ns, the following steps are taken:

1. If _ns_ is not a module namespace exotic object, throw a *TypeError* exception. 1. Let _module_ be _ns_.[[Module]]. 1. Let _entry_ be _module_.[[Entry]]. 1. Let _status_ be EnsureEvaluated(_entry_). 1. RejectIfAbrupt(_status_); 1. Return a promise resolved with *undefined*.

#### 8.4.2. Module.prototype

The value of Module.prototype is an ordinary object with a null [[Prototype]].

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

### 8.5. Properties of Module Instances

Module instances are module namespace exotic objects.

## 9. Local Loading

TODO:

- syntax for accessing module local information: `import local from this;`
- dynamic import: `local.import()`
- extending the hooks to handle `this`
- debugging info
- room for host environment-specific data

## 10. Browser Loader

Every host environment must implement a default loader object as the initial value of the loader property of the System object.

### 10.1. System.loader Object

The Default Browser Loader Object is an %BrowserLoader% instance, whose internal slots are set as if it had been constructed by the expression Construct(%BrowserLoader%).

## 11. BrowserLoader Objects

### 11.1. The BrowserLoader Constructor

The BrowserLoader constructor is the %BrowserLoader% intrinsic object. When called as a constructor it creates and initializes a new BrowserLoader object. When BrowserLoader is called as a function rather than as a constructor, it throws an exception.

### 11.2. Properties of the BrowserLoader Constructor

The value of the [[Prototype]] internal slot of the BrowserLoader constructor is the intrinsic object %FunctionPrototype%.

The BrowserLoader constructor has the following properties:

#### 11.2.1. BrowserLoader.prototype

The initial value of BrowserLoader.prototype is the intrinsic object %BrowserLoaderPrototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

### 11.3. Properties of the BrowserLoader Prototype

#### 11.3.1. BrowserLoader.prototype[ @@resolve ](name, referrer)

When the @@resolve method is called, the following steps are taken:

TODO: name resolution policy

- relative and site-relative URLs: `"./utils.js"`, `"/scripts/utils.js"`
- JS standard modules: `"std/math"`, `"std/json"`, `"std/reflect"`
- Web standard modules: `"web/worker"`, `"web/audio"`
- absolute URLs: `"https://cdn.example.com/jquery/v/2.0"`

The value of the name property of this function is "[Reflect.Loader.resolve]".

#### 11.3.2. BrowserLoader.prototype[ @@fetch ](entry, key)

When the @@fetch method is called, the following steps are taken:

TODO:

- reference fetch standard
- cross-origin produces an opaque object as in ServiceWorker
- CORS, CSP
- other kinds of web assets

The value of the name property of this function is "[Reflect.Loader.fetch]".

#### 11.3.3. BrowserLoader.prototype[ @@translate ](entry, payload)

When the @@translate method is called, the following steps are taken:

TODO: no-op.

The value of the name property of this function is "[Reflect.Loader.translate]".

#### 11.3.4. BrowserLoader.prototype[ @@instantiate ](entry, source)

When the @@instantiate method is called, the following steps are taken:

TODO:

- basically a no-op.
- but also needs to re-absorb opaque responses.

The value of the name property of this function is "[Reflect.Loader.instantiate]".

## Annexes

### List of Well-Known Intrinsic Objects

The intrinsics are listed in table below:

Intrinsic Name | Description (non-normative)
--- | ---
%Loader% | The loader constructor (3.1)
%LoaderPrototype% | The initial value of the *prototype* data property of %Loader% (3.2.1)
%BrowserLoader% | The browser loader constructor (11.1)
%BrowserLoaderPrototype% | The initial value of the *prototype* data property of %BrowserLoader% (11.2.1)
%Registry% | The registry constructor (4.2)
%RegistryPrototype% | The initial value of the *prototype* data property of %Registry% (4.3.1)
%ModuleStatus% | The module status constructor (5.2)
%ModuleStatusPrototype% | The initial value of the *prototype* data property of %ModuleStatus% (5.3.1)

Copyright © 1970 WHATWG (Apple, Google, Mozilla, Microsoft). This work is licensed under a Creative Commons Attribution 4.0 International License.

## Index

### Terms defined by this specification

- reflective module record, in §8.1
- stage, in §5.1.5