Stage 2 Draft / April 21, 2023

Module Declarations

1 Module Declarations

Editor's Note

This proposal builds on top of the Module Expressions proposal, which introduces the following production:

ModuleExpression : module [no LineTerminator here] { ModuleBodyopt }

Syntax

ModuleDeclaration[Default] : module [no LineTerminator here] Identifier { ModuleBodyopt } [+Default] module [no LineTerminator here] { ModuleBodyopt }

1.1 Runtime Semantics: Evaluation

ModuleDeclaration : module Identifier { ModuleBodyopt } module { ModuleBodyopt }
  1. Return empty.

8 Syntax-Directed Operations

8.2 Scope Analysis

8.2.1 Static Semantics: BoundNames

The syntax-directed operation BoundNames takes no arguments and returns a List of Strings. It is defined piecewise over the following productions:

ModuleDeclaration : module Identifier { ModuleBodyopt }
  1. Return the BoundNames of Identifier.
ModuleDeclaration : module { ModuleBodyopt }
  1. Return « "*default*" ».
ExportDeclaration : export default ModuleDeclaration
  1. Let declarationNames be the BoundNames of ModuleDeclaration.
  2. If declarationNames does not include the element "*default*", append "*default*" to declarationNames.
  3. Return declarationNames.

8.2.3 Static Semantics: IsConstantDeclaration

The syntax-directed operation IsConstantDeclaration takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

ModuleDeclaration : module Identifier { ModuleBodyopt } module { ModuleBodyopt }
  1. Return true.

8.2.5 Static Semantics: LexicallyScopedDeclarations

The syntax-directed operation LexicallyScopedDeclarations takes no arguments and returns a List of Parse Nodes. It is defined piecewise over the following productions:

Declaration : ModuleDeclaration
  1. Return a List whose sole element is ModuleDeclaration.

8.2.12 Static Semantics: ContainsUndefinedModuleReference

The syntax-directed operation ContainsUndefinedModuleReference takes argument declaredModules (a List of Strings) and returns a Boolean.

Unless explicitly specified otherwise, all nonterminals have an implicit definition for ContainsUndefinedModuleReference with argument declaredModules.The implicit definition applies ContainsUndefinedModuleReference with argument declaredModules to the nonterminal's inner nonterminals, and returns true if it's true for any of them. For example, ContainsUndefinedModuleReference of ExponentiationExpression is implicitly defined as follows:

ExponentiationExpression : UpdateExpression ** ExponentiationExpression
  1. Let hasUndefinedRef be ContainsUndefinedModuleReference of UpdateExpression with argument declaredModules.
  2. If hasUndefinedRef is true, return true.
  3. Return ContainsUndefinedModuleReference of ExponentiationExpression with argument declaredModules.

The following productions have a different definition of ContainsUndefinedModuleReference:

ModuleSpecifier : Identifier
  1. Let reference be the StringValue of Identifier.
  2. If reference is in declaredModules, return false.
  3. Return true.
ModuleBody : ModuleItemList
  1. Let localDeclaredModules be DeclaredModuleNames of ModuleItemList.
  2. Let lexNames be the LexicallyDeclaredNames of ModuleItemList.
  3. Let varNames be the VarDeclaredNames of ModuleItemList.
  4. Let visibleDeclaredModules be a new List containing the elements of declaredModules that are not in lexNames or varNames.
  5. Append all the elements of localDeclaredModules to visibleDeclaredModules.
  6. Return ContainsUndefinedModuleReference of ModuleItemList with argument visibleDeclaredModules.
ScriptBody : StatementList
  1. Assert: declaredModules is an empty List.
  2. Let localDeclaredModules be DeclaredModuleNames of StatementList.
  3. Return ContainsUndefinedModuleReference of StatementList with argument localDeclaredModules.
FunctionStatementList : StatementList ClassStaticBlockStatementList : StatementList Block : { StatementList }
  1. Let lexNames be the LexicallyDeclaredNames of StatementList.
  2. Let varNames be the VarDeclaredNames of StatementList.
  3. Let localDeclaredModules be the DeclaredModuleNames of StatementList.
  4. Let visibleDeclaredModules be a new List containing the elements of declaredModules that are not in lexNames or varNames.
  5. Append each element of localDeclaredModules to visibleDeclaredModules.
  6. Return ContainsUndefinedModuleReference of StatementList with argument visibleDeclaredModules.
FunctionStatementList : [empty] ClassStaticBlockStatementList : [empty] Block : { }
  1. Return false.
FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } function ( FormalParameters ) { FunctionBody } FunctionExpression : function BindingIdentifieropt ( FormalParameters ) { FunctionBody }
  1. If BindingIdentifier is present, return ContainsUndefinedModuleReferenceInFunction(declaredModules, FormalParameters, FunctionBody, BindingIdentifier).
  2. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, FormalParameters, FunctionBody).
MethodDefinition : ClassElementName ( UniqueFormalParameters ) { FunctionBody }
  1. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, FunctionBody).
MethodDefinition : set ClassElementName ( PropertySetParameterList ) { FunctionBody }
  1. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, PropertySetParameterList, FunctionBody).
GeneratorDeclaration : function BindingIdentifier * ( UniqueFormalParameters ) { GeneratorBody } function * ( UniqueFormalParameters ) { GeneratorBody } GeneratorExpression : function BindingIdentifieropt * ( UniqueFormalParameters ) { GeneratorBody } GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody }
  1. If BindingIdentifier is present, return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, GeneratorBody, BindingIdentifier).
  2. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, GeneratorBody).
AsyncFunctionDeclaration : async function BindingIdentifier ( UniqueFormalParameters ) { AsyncFunctionBody } async function ( UniqueFormalParameters ) { AsyncFunctionBody } AsyncFunctionExpression : async function BindingIdentifieropt ( UniqueFormalParameters ) { AsyncFunctionBody } AsyncMethod : async ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }
  1. If BindingIdentifier is present, return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, AsyncFunctionBody, BindingIdentifier).
  2. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, AsyncFunctionBody).
AsyncGeneratorDeclaration : async function BindingIdentifier * ( UniqueFormalParameters ) { AsyncGeneratorBody } async function * ( UniqueFormalParameters ) { AsyncGeneratorBody } AsyncGeneratorExpression : async function BindingIdentifieropt * ( UniqueFormalParameters ) { AsyncGeneratorBody } AsyncGeneratorMethod : async * ClassElementName ( UniqueFormalParameters ) { AsyncGeneratorBody }
  1. If BindingIdentifier is present, return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, AsyncGeneratorBody, BindingIdentifier).
  2. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, UniqueFormalParameters, AsyncGeneratorBody).
ArrowFunction : ArrowParameters => ConciseBody
  1. If ArrowParameters is BindingIdentifier, let params be BindingIdentifier.
  2. Else,
    1. Let cover be the CoverParenthesizedExpressionAndArrowParameterList of ArrowParameters.
    2. Let params be the ArrowFormalParameters that is covered by cover.
  3. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, params, ConciseBody).
AsyncArrowFunction : async AsyncArrowBindingIdentifier => AsyncConciseBody
  1. Let params be the BindingIdentifier of AsyncArrowBindingIdentifier.
  2. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, params, AsyncConciseBody).
AsyncArrowFunction : CoverCallExpressionAndAsyncArrowHead => AsyncConciseBody
  1. Let head be the AsyncArrowHead that is covered by CoverCallExpressionAndAsyncArrowHead.
  2. Let params be the ArrowFormalParameters of head.
  3. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, params, AsyncConciseBody).
ClassDeclaration : class BindingIdentifier ClassTail class ClassTail ClassExpression : class BindingIdentifieropt ClassTail
  1. Let visibleDeclaredModules be declaredModules.
  2. If BindingIdentifier is present, then
    1. Let id be the StringValue of BindingIdentifier.
    2. Set visibleDeclaredModules to a new List containing the elements of declaredModules that are not equal to id.
  3. Return ContainsUndefinedModuleReference of ClassTail with argument visibleDeclaredModules.
Catch : catch ( CatchParameter ) Block
  1. Return ContainsUndefinedModuleReferenceInFunction(declaredModules, CatchParameter, Block).

8.2.12.1 ContainsUndefinedModuleReferenceInFunction ( declaredModules, params, body [ , binding ] )

The abstract operation ContainsUndefinedModuleReferenceInFunction takes arguments declaredModules (a List of Strings), params (a Parse Node), and body (a Parse Node) and optional argument binding (a Parse Node) and returns a Boolean. It performs the following steps when called:

  1. Let boundNames be the BoundNames of params.
  2. If binding is present, append the StringValue of binding to boundNames.
  3. Let visibleDeclaredModules be a new List containing the elements of declaredModules that are not in boundNames.
  4. If ContainsUndefinedModuleReference of params with argument visibleDeclaredModules is true, return true.
  5. Let localDeclaredModules be the DeclaredModuleNames of StatementList.
  6. Append each element of localDeclaredModules to visibleDeclaredModules.
  7. Return ContainsUndefinedModuleReference of body with argument visibleDeclaredModules is true.

8.2.13 Static Semantics: DeclaredModuleNames

The syntax-directed operation DeclaredModuleNames takes no arguments and returns a List of Strings. It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. Let names1 be DeclaredModuleNames of ModuleItemList.
  2. Let names2 be DeclaredModuleNames of ModuleItem.
  3. Return the list-concatenation of names1 and names2.
StatementList : StatementList StatementListItem
  1. Let names1 be DeclaredModuleNames of StatementList.
  2. Let names2 be DeclaredModuleNames of StatementListItem.
  3. Return the list-concatenation of names1 and names2.
StatementListItem : Statement
  1. Return a new empty List.
Declaration : HoistableDeclaration LexicalDeclaration ClassDeclaration
  1. Return a new empty List.
Declaration : ModuleDeclaration
  1. Return BoundNames of ModuleDeclaration.
ModuleItem : ImportDeclaration
  1. Return the BoundNames of ImportDeclaration.
Note
DeclaredModuleNames includes all the imported bindings, so that using them as import specifiers doesn't throw when parsing the module. However, they will be validated when linking by LoadInternalModule.

8.2.14 Static Semantics: TopLevelModuleDeclarations

The syntax-directed operation TopLevelModuleDeclarations takes no arguments and returns a List of ModuleDeclaration Parse Node. It is defined piecewise over the following productions:

ModuleItemList : ModuleItemList ModuleItem
  1. Let decls1 be TopLevelModuleDeclarations of ModuleItemList.
  2. Let decls2 be TopLevelModuleDeclarations of ModuleItem.
  3. Return the list-concatenation of decls1 and decls2.
ModuleItem : Statement ModuleItem : ImportDeclaration
  1. Return a new empty List.
Declaration : ModuleDeclaration
  1. Return a new List whose sole element is ModuleDeclaration.
Declaration : HoistableDeclaration LexicalDeclaration ClassDeclaration
  1. Return a new empty List.
ExportDeclaration : export default ModuleDeclaration
  1. Return a new List whose sole element is ModuleDeclaration.
ExportDeclaration : export ExportFromClause FromClause ; export NamedExports ; export VariableStatement export default HoistableDeclaration export default ClassDeclaration export default AssignmentExpression ;
  1. Return a new empty List.

8.2.15 Static Semantics: ParseInnerModules

The syntax-directed operation ParseInnerModules takes argument declaredModules (a List of Records) and returns unused.

Unless explicitly specified otherwise, all nonterminals have an implicit definition for ParseInnerModules with argument declaredModules.The implicit definition applies ParseInnerModules with argument declaredModules to the nonterminal's inner nonterminals. For example, ContainsUndefinedModuleReference of ExponentiationExpression is implicitly defined as follows:

ExponentiationExpression : UpdateExpression ** ExponentiationExpression
  1. Perform ParseInnerModules of UpdateExpression with argument declaredModules.
  2. Perform ParseInnerModules of ExponentiationExpression with argument declaredModules.

The following productions have a different definition of ContainsUndefinedModuleReference:

ModuleSpecifier : Identifier
  1. Let reference be the StringValue of Identifier.
  2. If reference is in declaredModules, return false.
  3. Return true.
ModuleBody : ModuleItemList
  1. Let localDeclaredModules be DeclaredModuleNames of ModuleItemList.
  2. Let lexNames be the LexicallyDeclaredNames of ModuleItemList.
  3. Let varNames be the VarDeclaredNames of ModuleItemList.
  4. Let visibleDeclaredModules be a new List containing the elements of declaredModules that are not in lexNames or varNames.
  5. Append all the elements of localDeclaredModules to visibleDeclaredModules.
  6. Return ContainsUndefinedModuleReference of ModuleItemList with argument visibleDeclaredModules.
ScriptBody : StatementList
  1. Assert: declaredModules is an empty List.
  2. Let localDeclaredModules be DeclaredModuleNames of StatementList.
  3. Return ContainsUndefinedModuleReference of StatementList with argument localDeclaredModules.
Block : { }
  1. Return false.
Block : { StatementList }
  1. Let lexNames be the LexicallyDeclaredNames of StatementList.
  2. Let visibleDeclaredModules be a new List containing the elements of declaredModules that are not in lexNames.
  3. Return ContainsUndefinedModuleReference of StatementList with argument visibleDeclaredModules.

9 Executable Code and Execution Contexts

9.1 Environment Records

Environment Record is a specification type used to define the association of Identifiers to specific variables and functions, based upon the lexical nesting structure of ECMAScript code. Usually an Environment Record is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement. Each time such code is evaluated, a new Environment Record is created to record the identifier bindings that are created by that code.

Every Environment Record has an [[OuterEnv]] field, which is either null or a reference to an outer Environment Record. This is used to model the logical nesting of Environment Record values. The outer reference of an (inner) Environment Record is a reference to the Environment Record that logically surrounds the inner Environment Record. An outer Environment Record may, of course, have its own outer Environment Record. An Environment Record may serve as the outer environment for multiple inner Environment Records. For example, if a FunctionDeclaration contains two nested FunctionDeclarations then the Environment Records of each of the nested functions will have as their outer Environment Record the Environment Record of the current evaluation of the surrounding function.

Environment Records are purely specification mechanisms and need not correspond to any specific artefact of an ECMAScript implementation. It is impossible for an ECMAScript program to directly access or manipulate such values.

Each Environment Record has the fields listed in Table 1.

Table 1: Fields of Environment Records
Field Type Purpose
[[OuterEnv]] an Environment Record or null
[[ModuleDeclarations]] a List of Records with fields [[Name]] (a String) and [[Module]] (a Module Record)

9.1.1 Environment Record Operations

The following abstract operations are used in this specification to operate upon Environment Records:

9.1.1.1 AddModuleDeclaration ( name, module, env )

The abstract operation AddModuleDeclaration takes arguments name (a String), module (a Module Record), and env (an Environment Record) and returns unused. It performs the following steps when called:

  1. Append the Record { [[Name]]: name, [[Module]]: module } to env.[[ModuleDeclarations]].
  2. Return unused.

9.1.1.2 ResolveModuleDeclaration ( name, env )

The abstract operation ResolveModuleDeclaration takes arguments name (a String) and env (an Environment Record) and returns either a normal completion containing a Module Record, or a throw completion. It performs the following steps when called:

  1. Let moduleDeclarations be env.[[ModuleDeclarations]].
  2. For each Record m in moduleDeclarations, do
    1. If m.[[Name]] is name, return m.[[Module]].
  3. If env.HasBinding(name), throw a ReferenceError exception.
  4. If env is a Module Environment Record or a Global Environment Record, throw a ReferenceError exception.
  5. Assert: env.[[OuterEnv]] is not null.
  6. Return ? ResolveModuleDeclaration(name, env.[[OuterEnv]]).

10 Ordinary and Exotic Objects Behaviours

10.2 ECMAScript Function Objects

10.2.11 FunctionDeclarationInstantiation ( func, argumentsList )

The abstract operation FunctionDeclarationInstantiation takes arguments func (a function object) and argumentsList (a List of ECMAScript language values) and returns either a normal completion containing unused or an abrupt completion. func is the function object for which the execution context is being established. It performs the following steps when called:

  1. Let calleeContext be the running execution context.
  2. Let code be func.[[ECMAScriptCode]].
  3. Let strict be func.[[Strict]].
  4. Let formals be func.[[FormalParameters]].
  5. Let parameterNames be the BoundNames of formals.
  6. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false.
  7. Let simpleParameterList be IsSimpleParameterList of formals.
  8. Let hasParameterExpressions be ContainsExpression of formals.
  9. Let varNames be the VarDeclaredNames of code.
  10. Let varDeclarations be the VarScopedDeclarations of code.
  11. Let lexicalNames be the LexicallyDeclaredNames of code.
  12. Let functionNames be a new empty List.
  13. Let functionsToInitialize be a new empty List.
  14. For each element d of varDeclarations, in reverse List order, do
    1. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
      1. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
      2. Let fn be the sole element of the BoundNames of d.
      3. If fn is not an element of functionNames, then
        1. Insert fn as the first element of functionNames.
        2. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
        3. Insert d as the first element of functionsToInitialize.
  15. Let argumentsObjectNeeded be true.
  16. If func.[[ThisMode]] is lexical, then
    1. NOTE: Arrow functions never have an arguments object.
    2. Set argumentsObjectNeeded to false.
  17. Else if "arguments" is an element of parameterNames, then
    1. Set argumentsObjectNeeded to false.
  18. Else if hasParameterExpressions is false, then
    1. If "arguments" is an element of functionNames or if "arguments" is an element of lexicalNames, then
      1. Set argumentsObjectNeeded to false.
  19. If strict is true or if hasParameterExpressions is false, then
    1. NOTE: Only a single Environment Record is needed for the parameters, since calls to eval in strict mode code cannot create new bindings which are visible outside of the eval.
    2. Let env be the LexicalEnvironment of calleeContext.
  20. Else,
    1. NOTE: A separate Environment Record is needed to ensure that bindings created by direct eval calls in the formal parameter list are outside the environment where parameters are declared.
    2. Let calleeEnv be the LexicalEnvironment of calleeContext.
    3. Let env be NewDeclarativeEnvironment(calleeEnv).
    4. Assert: The VariableEnvironment of calleeContext is calleeEnv.
    5. Set the LexicalEnvironment of calleeContext to env.
  21. For each String paramName of parameterNames, do
    1. Let alreadyDeclared be ! env.HasBinding(paramName).
    2. NOTE: Early errors ensure that duplicate parameter names can only occur in non-strict functions that do not have parameter default values or rest parameters.
    3. If alreadyDeclared is false, then
      1. Perform ! env.CreateMutableBinding(paramName, false).
      2. If hasDuplicates is true, then
        1. Perform ! env.InitializeBinding(paramName, undefined).
  22. If argumentsObjectNeeded is true, then
    1. If strict is true or if simpleParameterList is false, then
      1. Let ao be CreateUnmappedArgumentsObject(argumentsList).
    2. Else,
      1. NOTE: A mapped argument object is only provided for non-strict functions that don't have a rest parameter, any parameter default value initializers, or any destructured parameters.
      2. Let ao be CreateMappedArgumentsObject(func, formals, argumentsList, env).
    3. If strict is true, then
      1. Perform ! env.CreateImmutableBinding("arguments", false).
      2. NOTE: In strict mode code early errors prevent attempting to assign to this binding, so its mutability is not observable.
    4. Else,
      1. Perform ! env.CreateMutableBinding("arguments", false).
    5. Perform ! env.InitializeBinding("arguments", ao).
    6. Let parameterBindings be the list-concatenation of parameterNames and « "arguments" ».
  23. Else,
    1. Let parameterBindings be parameterNames.
  24. Let iteratorRecord be CreateListIteratorRecord(argumentsList).
  25. If hasDuplicates is true, then
    1. Perform ? IteratorBindingInitialization of formals with arguments iteratorRecord and undefined.
  26. Else,
    1. Perform ? IteratorBindingInitialization of formals with arguments iteratorRecord and env.
  27. If hasParameterExpressions is false, then
    1. NOTE: Only a single Environment Record is needed for the parameters and top-level vars.
    2. Let instantiatedVarNames be a copy of the List parameterBindings.
    3. For each element n of varNames, do
      1. If n is not an element of instantiatedVarNames, then
        1. Append n to instantiatedVarNames.
        2. Perform ! env.CreateMutableBinding(n, false).
        3. Perform ! env.InitializeBinding(n, undefined).
    4. Let varEnv be env.
  28. Else,
    1. NOTE: A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body.
    2. Let varEnv be NewDeclarativeEnvironment(env).
    3. Set the VariableEnvironment of calleeContext to varEnv.
    4. Let instantiatedVarNames be a new empty List.
    5. For each element n of varNames, do
      1. If n is not an element of instantiatedVarNames, then
        1. Append n to instantiatedVarNames.
        2. Perform ! varEnv.CreateMutableBinding(n, false).
        3. If n is not an element of parameterBindings or if n is an element of functionNames, let initialValue be undefined.
        4. Else,
          1. Let initialValue be ! env.GetBindingValue(n, false).
        5. Perform ! varEnv.InitializeBinding(n, initialValue).
        6. NOTE: A var with the same name as a formal parameter initially has the same value as the corresponding initialized parameter.
  29. NOTE: Annex B.3.2.1 adds additional steps at this point.
  30. If strict is false, then
    1. Let lexEnv be NewDeclarativeEnvironment(varEnv).
    2. NOTE: Non-strict functions use a separate Environment Record for top-level lexical declarations so that a direct eval can determine whether any var scoped declarations introduced by the eval code conflict with pre-existing top-level lexically scoped declarations. This is not needed for strict functions because a strict direct eval always places all declarations into a new Environment Record.
  31. Else, let lexEnv be varEnv.
  32. Set the LexicalEnvironment of calleeContext to lexEnv.
  33. Let outerModuleDeclarations be the outer module declarations, obtained using ResolveModuleDeclaration (TODO: define how).
  34. Let moduleHostDefined be null.
  35. Let currentScriptOrModule be GetActiveScriptOrModule().
  36. If currentScriptOrModule is not null, set moduleHostDefined to currentScriptOrModule.[[HostDefined]].
  37. Let localModuleDeclarations be InstantiateModuleDeclarations(code, the current Realm Record, moduleHostDefined, outerModuleDeclarations).
  38. Let lexDeclarations be the LexicallyScopedDeclarations of code.
  39. For each element d of lexDeclarations, do
    1. NOTE: A lexically declared name cannot be the same as a function/generator declaration, formal parameter, or a var name. Lexically declared names are only instantiated here but not initialized.
    2. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! lexEnv.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! lexEnv.CreateMutableBinding(dn, false).
  40. Let privateEnv be the PrivateEnvironment of calleeContext.
  41. For each Record m in localModuleDeclarations, do
    1. Perform AddModuleDeclaration(m.[[Name]], _m.[[Module]], env).
    2. Let mo be GetModuleObject(m.[[Module]]).
    3. Perform ! env.InitializeBinding(m.[[Name]], mo).
  42. For each Parse Node f of functionsToInitialize, do
    1. Let fn be the sole element of the BoundNames of f.
    2. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
    3. Perform ! varEnv.SetMutableBinding(fn, fo, false).
  43. Return unused.
Note

B.3.2 provides an extension to the above algorithm that is necessary for backwards compatibility with web browser implementations of ECMAScript that predate ECMAScript 2015.

14 ECMAScript Language: Statements and Declarations

Syntax

Declaration[Yield, Await] : HoistableDeclaration[?Yield, ?Await, ~Default] ClassDeclaration[?Yield, ?Await, ~Default] LexicalDeclaration[+In, ?Yield, ?Await] ModuleDeclaration[~Default]

14.2 Block

14.2.3 BlockDeclarationInstantiation ( code, env )

The abstract operation BlockDeclarationInstantiation takes arguments code (a Parse Node) and env (a Declarative Environment Record) and returns unused. code is the Parse Node corresponding to the body of the block. env is the Environment Record in which bindings are to be created.

It performs the following steps when called:

  1. Let outerModuleDeclarations be the outer module declarations, obtained using ResolveModuleDeclaration (TODO: define how).
  2. Let moduleHostDefined be null.
  3. Let currentScriptOrModule be GetActiveScriptOrModule().
  4. If currentScriptOrModule is not null, set moduleHostDefined to currentScriptOrModule.[[HostDefined]].
  5. Let localModuleDeclarations be InstantiateModuleDeclarations(code, the current Realm Record, moduleHostDefined, outerModuleDeclarations).
  6. Let declarations be the LexicallyScopedDeclarations of code.
  7. Let privateEnv be the running execution context's PrivateEnvironment.
  8. For each element d of declarations, do
    1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! env.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! env.CreateMutableBinding(dn, false). NOTE: This step is replaced in section B.3.2.6.
    2. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
      1. Let fn be the sole element of the BoundNames of d.
      2. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
      3. Perform ! env.InitializeBinding(fn, fo). NOTE: This step is replaced in section B.3.2.6.
  9. For each Record m in localModuleDeclarations, do
    1. Perform AddModuleDeclaration(m.[[Name]], _m.[[Module]], env).
    2. Let mo be GetModuleObject(m.[[Module]]).
    3. Perform ! env.InitializeBinding(m.[[Name]], mo).
  10. Return unused.

16 ECMAScript Language: Scripts and Modules

16.1 Scripts

16.1.1 Static Semantics: Early Errors

Script : ScriptBody

16.1.4 Script Records

A Script Record encapsulates information about a script being evaluated. Each script record contains the fields listed in Table 2.

Table 2: Script Record Fields
Field Name Value Type Meaning
[[Realm]] a Realm Record or undefined
[[ECMAScriptCode]] a Parse Node
[[LoadedModules]] a List of Records with fields [[Specifier]] (a StringModuleSpecifier Record) and [[Module]] (a Module Record)
[[HostDefined]] anything (default value is empty)

16.1.7 GlobalDeclarationInstantiation ( script, env )

The abstract operation GlobalDeclarationInstantiation takes arguments script (a Script Parse Node) and env (a Global Environment Record) and returns either a normal completion containing unused or a throw completion. script is the Script for which the execution context is being established. env is the global environment in which bindings are to be created. It performs the following steps when called:

  1. Let lexNames be the LexicallyDeclaredNames of script.
  2. Let varNames be the VarDeclaredNames of script.
  3. For each element name of lexNames, do
    1. If env.HasVarDeclaration(name) is true, throw a SyntaxError exception.
    2. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
    3. Let hasRestrictedGlobal be ? env.HasRestrictedGlobalProperty(name).
    4. If hasRestrictedGlobal is true, throw a SyntaxError exception.
  4. For each element name of varNames, do
    1. If env.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
  5. Let varDeclarations be the VarScopedDeclarations of script.
  6. Let functionsToInitialize be a new empty List.
  7. Let declaredFunctionNames be a new empty List.
  8. For each element d of varDeclarations, in reverse List order, do
    1. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then
      1. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration.
      2. NOTE: If there are multiple function declarations for the same name, the last declaration is used.
      3. Let fn be the sole element of the BoundNames of d.
      4. If fn is not an element of declaredFunctionNames, then
        1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn).
        2. If fnDefinable is false, throw a TypeError exception.
        3. Append fn to declaredFunctionNames.
        4. Insert d as the first element of functionsToInitialize.
  9. Let declaredVarNames be a new empty List.
  10. For each element d of varDeclarations, do
    1. If d is a VariableDeclaration, a ForBinding, or a BindingIdentifier, then
      1. For each String vn of the BoundNames of d, do
        1. If vn is not an element of declaredFunctionNames, then
          1. Let vnDefinable be ? env.CanDeclareGlobalVar(vn).
          2. If vnDefinable is false, throw a TypeError exception.
          3. If vn is not an element of declaredVarNames, then
            1. Append vn to declaredVarNames.
  11. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. However, if the global object is a Proxy exotic object it may exhibit behaviours that cause abnormal terminations in some of the following steps.
  12. NOTE: Annex B.3.2.2 adds additional steps at this point.
  13. Let localModuleDeclarations be InstantiateModuleDeclarations(script, script.[[Realm]], script.[[HostDefined]], a new empty List).
  14. Let lexDeclarations be the LexicallyScopedDeclarations of script.
  15. Let privateEnv be null.
  16. For each element d of lexDeclarations, do
    1. NOTE: Lexically declared names are only instantiated here but not initialized.
    2. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ? env.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ? env.CreateMutableBinding(dn, false).
  17. For each Record m of localModuleDeclarations, do
    1. Perform AddModuleDeclaration(m.[[Name]], _m.[[Module]], env).
    2. Let mo be GetModuleObject(m.[[Module]]).
    3. Perform ! env.InitializeBinding(m.[[Name]], mo).
  18. For each Parse Node f of functionsToInitialize, do
    1. Let fn be the sole element of the BoundNames of f.
    2. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
    3. Perform ? env.CreateGlobalFunctionBinding(fn, fo, false).
  19. For each String vn of declaredVarNames, do
    1. Perform ? env.CreateGlobalVarBinding(vn, false).
  20. Return unused.
Note

Early errors specified in 16.1.1 prevent name conflicts between function/var declarations and let/const/class/module declarations as well as redeclaration of let/const/class/module bindings for declaration contained within a single Script. However, such conflicts and redeclarations that span more than one Script are detected as runtime errors during GlobalDeclarationInstantiation. If any such errors are detected, no bindings are instantiated for the script. However, if the global object is defined using Proxy exotic objects then the runtime tests for conflicting declarations may be unreliable resulting in an abrupt completion and some global declarations not being instantiated. If this occurs, the code for the Script is not evaluated.

Unlike explicit var or function declarations, properties that are directly created on the global object result in global bindings that may be shadowed by let/const/class/module declarations.

16.2 Modules

16.2.1 Module Semantics

16.2.1.1 Static Semantics: Early Errors

Module : ModuleBody

16.2.1.3 Static Semantics: ModuleRequests

The syntax-directed operation ModuleRequests takes no arguments and returns a List of Strings. It is defined piecewise over the following productions:

ModuleSpecifier : StringLiteral
  1. Return a List whose sole element is the SV of StringLiteralModuleSpecifier Record { [[Name]]: the SV of StringLiteral, [[Type]]: external }.
ModuleSpecifier : Identifier
  1. Return a List whose sole element is the ModuleSpecifier Record { [[Name]]: the StringValue of Identifier, [[Type]]: internal }.

16.2.1.4 Abstract Module Records

Table 3: Abstract Methods of Module Records
Method Purpose
GetExportedNames([exportStarSet])
ResolveExport(exportName [, resolveSet])
GetExportedModule(name)

Return the Module Record for the module exported by this module as name. If this module is a Cyclic Module Record, it can also return an ImportedModule Record representing a potential module which has been re-exported by a transitive dependency. It throws an error if there is no potential module export corresponding to name.

Unless otherwise specified, the default implementation of this method is:

  1. Throw a TypeError exception.
LoadRequestedModules( [ hostDefined ] )
Link()
Evaluate()

16.2.1.4.1 GetModuleObject ( moduleRecord )

The abstract operation GetModuleObject takes argument moduleRecord (a Module Record) and returns a Module Object. It creates the Module Object corresponding to the moduleRecord Module Record. It performs the following steps when called:

  1. Let moduleObject be OrdinaryObjectCreate(%Module.prototype%, « [[ModuleRecord]] »).
  2. Set moduleObject.[[ModuleRecord]] to moduleRecord.

16.2.1.5 Cyclic Module Records

In addition to the fields defined in Table 40 Cyclic Module Records have the additional fields listed in Table 4

Table 4: Additional Fields of Cyclic Module Records
Field Name Value Type Meaning
[[Status]] new, unlinked, linking, linked, evaluating, evaluating-async, or evaluated
[[EvaluationError]] a throw completion or empty
[[DFSIndex]] an integer or empty
[[DFSAncestorIndex]] an integer or empty
[[RequestedModules]] a List of StringsModuleSpecifier Records A List of Records representing all the ModuleSpecifier strings or identifiers used by the module represented by this record to request the importation of a module. The List is in source text occurrence order.
[[LoadedModules]] a List of Records with fields [[Specifier]] (a StringModuleSpecifier Record) and [[Module]] (a Module Record) A map from the specifier strings used by the module represented by this record to request the importation of a module to the resolved Module Record. The list does not contain two different Records with the same [[Specifier]].
[[CycleRoot]] a Cyclic Module Record or empty
[[HasTLA]] a Boolean
[[AsyncEvaluation]] a Boolean
[[TopLevelCapability]] a PromiseCapability Record or empty
[[AsyncParentModules]] a List of Cyclic Module Records
[[PendingAsyncDependencies]] an integer or empty

In addition to the methods defined in Table 3 Cyclic Module Records have the additional methods listed in Table 5

Table 5: Additional Abstract Methods of Cyclic Module Records
Method Purpose
LoadInternalModule( name )

Loads the internal module with the given name and returns a Module Record or, if the internal module could be imported from another module, an ImportedModule Record. It throws if an internal module named name does ot exist.

Unless otherwise specified, the default implementation of this method is:

  1. Throw a TypeError exception.
InitializeEnvironment()
ExecuteModule( [ promiseCapability ] )

A ModuleSpecifier Record represents the request to import a module. Each ModuleSpecifier Record has the fields defined in Table 6:

Table 6: ModuleSpecifier Record Fields
Field Name Value Type Meaning
[[Name]] a String The name of the imported module. For example, it's the string "foo" in import "foo";
[[Type]] internal or external Whether the module is an internal module, that should be declared nested inside another module, or an external module, that should be loaded using the HostLoadImportedModule abstract operation.

An ImportedModule Record represents a module which is imported from another module. Each ImportedModule Record has the fields defined in Table 7:

Table 7: ImportedModule Record Fields
Field Name Value Type Meaning
[[Specifier]] a ModuleSpecifier Record The specifier of the module this module is imported from.
[[ImportName]] a String The name of the imported module.

A GraphLoadingState Record is a Record that contains information about the loading process of a module graph. It's used to continue loading after a call to HostLoadImportedModule. Each GraphLoadingState Record has the fields defined in Table 8:

Table 8: GraphLoadingState Record Fields
Field Name Value Type Meaning
[[PromiseCapability]] a PromiseCapability Record The promise to resolve when the loading process finishes.
[[IsLoading]] a Boolean It is true if the loading process has not finished yet, neither successfully nor with an error.
[[PendingModulesCount]] a non-negative integer It tracks the number of pending HostLoadImportedModule calls.
[[Visited]] a List of Cyclic Module Records It is a list of the Cyclic Module Records that have been already loaded by the current loading process, to avoid infinite loops with circular dependencies.
[[HostDefined]] anything (default value is empty) It contains host-defined data to pass from the LoadRequestedModules caller to HostLoadImportedModule.

A BlockedInternalImport Record represents an import from an internal module that cannot be handled, because the internal module is imported from another module that hasn't been loaded yet. Each BlockedInternalImport Record has the fields defined in Table 9:

Table 9: BlockedInternalImport Record Fields
Field Name Value Type Meaning
[[BlockerReferrer]] a Module Record [[BlockerReferrer]] and [[BlockerSpecifier]] together indicate the module that is currently preventing the internal module from being imported.
[[BlockedSpecifier]] a ModuleSpecifier Record
[[ImportName]] a String It is the name of the expected module exported by ([[BlockerReferrer]], [[BlockerSpecifier]]).
[[BlockedReferrer]] a Cyclic Module Record It is the module that is currently blocked from importing the internal module.
[[LocalName]] a String It is the local alias, in [[BlockedReferrer]], of the imported module.
Note

To better understand the contents of BlockedInternalImport Records, consider the three modules defined in Table 10:

Table 10: BlockedInternalImport Record Example
Module Source
A
import { mod as module } from "B";import { value } from module;
B
export { myModule as mod } from "C";
C
export module myModule {export const value = 1;}

Assume that the loading process of external modules is asynchronous. When loading the dependencies of A, module cannot be resolved yet and it will be represented by the BlockedInternalImport Record { [[BlockerReferrer]]: A, [[BlockerSpecifier]]: the ModuleSpecifier Record { [[Type]]: external, [[Name]]: "B" }, [[ImportName]]: "mod", [[BlockedReferrer]]: A,[[LocalName]]: "module" }.

When B is loaded, module cannot be imported yet, because mod is not defined in B but in one of its dependencies: the above BlockedInternalImport Record will be replaced by the BlockedInternalImport Record { [[BlockerReferrer]]: B, [[BlockerSpecifier]]: the ModuleSpecifier Record { [[Type]]: external, [[Name]]: "C" }, [[ImportName]]: "myModule", [[BlockedReferrer]]: A, [[LocalName]]: "module" }.

Finally, after C has finished loading, it's possible to load the module internal module. This logic is handled in the below InnerModuleLoading and ProcessBlockedInternalRequests algorithms.

16.2.1.5.1 LoadRequestedModules ( [ hostDefined ] )

The LoadRequestedModules concrete method of Cyclic Module Record takes optional argument hostDefined (anything) and returns a Promise object.

16.2.1.5.1.1 InnerModuleLoading ( state, module [ , referrer [ , specifier ] ] )

The abstract operation InnerModuleLoading takes arguments state (a GraphLoadingState Record) and module (a Module Record) and optional arguments referrer (a Cyclic Module Record) and specifier (a ModuleSpecifier Record) and returns unused. It is used by LoadRequestedModules to recursively perform the actual loading process for module's dependency graph. It performs the following steps when called:

  1. Assert: state.[[IsLoading]] is true.
  2. If referrer has been provided, then
    1. Assert: specifier has been provided.
    2. Perform ProcessBlockedInternalRequests(state, referrer, specifier, module).
    3. If state.[[IsLoading]] is false, return.
  3. If module is a Cyclic Module Record, module.[[Status]] is new, and state.[[Visited]] does not contain module, then
    1. Append module to state.[[Visited]].
    2. Let requestedModulesCount be the length of module.[[RequestedModules]].
    3. Set state.[[PendingModules]] to state.[[PendingModules]] + requestedModulesCount.
    4. For each ModuleSpecifier Record required of module.[[RequestedModules]], do
      1. If state.[[IsLoading]] is true, then:
      2. If module.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is required, then
        1. Perform InnerModuleLoading(state, record.[[Module]], module, required).
      3. Else if required.[[Type]] is internal, then
        1. Let internalCompletion be Completion(module.LoadInternalModule(required.[[Name]])).
        2. If AbortModuleLoading(state, internalCompletion) is true, return.
        3. Let internal be internalCompletion.[[Value]].
        4. If internal is a Module Record, then
          1. Append Record { [[Specifier]]: required, [[Module]]: internal } to module.[[LoadedModules]].
          2. Perform InnerModuleLoading(state, internal, module, required).
        5. Else,
          1. Assert: internal is an ImportedModule Record.
          2. Append the Record { [[BlockerReferrer]]: module, [[BlockerSpecifier]]: internal.[[Specifier]], [[ImportName]]: internal.[[ImportName]], [[BlockedReferrer]]: module, [[LocalName]]: required.[[Name]] } to state.[[BlockedInternalImports]].
      4. Else,
        1. Assert: required.[[Type]] is external.
        2. Perform HostLoadImportedModule(module, requiredrequired.[[Name]], state.[[HostDefined]], state).
        3. NOTE: HostLoadImportedModule will call ContinueModuleLoading.
      5. If state.[[IsLoading]] is false, return.
  4. If state.[[IsLoading]] is false, return.
  5. Assert: state.[[PendingModules]] ≥ 1.
  6. Set state.[[PendingModules]] to state.[[PendingModules]] - 1.
  7. If state.[[PendingModules]] = 0, then
    1. Set state.[[IsLoading]] to false.
    2. For each Cyclic Module Record loaded in state.[[Visited]], do
      1. If loaded.[[Status]] is new, set loaded.[[Status]] to unlinked.
    3. Perform ! Call(state.[[PromiseCapability]].[[Resolve]], undefined, « undefined »).

16.2.1.5.1.2 ContinueModuleLoading ( state, referrer, specifier, moduleCompletion )

The abstract operation ContinueModuleLoading takes arguments state (a GraphLoadingState Record), referrer (a Cyclic Module Record), specifier (a ModuleSpecifier Record), and moduleCompletion (either a normal completion containing a Module Record or a throw completion) and returns unused. It is used to re-enter the loading process after a call to HostLoadImportedModule. It performs the following steps when called:

  1. If state.[[IsLoading]] is false, return.
  2. If AbortModuleLoading(state, moduleCompletion) is true, return.
  3. Assert: moduleCompletion is a normal completion.
  4. If moduleCompletion is a normal completion, then:
  5. Perform InnerModuleLoading(state, moduleCompletion.[[Value]], referrer, specifier).
  6. Else,
    1. Set state.[[IsLoading]] to false.
    2. Perform ! Call(state.[[PromiseCapability]].[[Reject]], undefined, « moduleCompletion.[[Value]] »).
  7. Return unused.

16.2.1.5.1.3 ProcessBlockedInternalRequests ( state, referrer, specifier, module )

The abstract operation ProcessBlockedInternalRequests takes arguments state (a GraphLoadingState Record), referrer (a Cyclic Module Record), specifier (a ModuleSpecifier Record), and module (a Module Record) and returns unused. It performs the following steps when called:

  1. For each Record dep of state.[[BlockedInternalImports]] such that dep.[[BlockerReferrer]] is referrer and dep.[[BlockerSpecifier]] is specifier, do
    1. Let exportedCompletion be Completion(module.GetExportedModule(dep.[[ImportName]])).
    2. If AbortModuleLoading(state, exportedCompletion) is true, return.
    3. Assert: exportedCompletion is a normal completion.
    4. Let exported be exportedCompletion.[[Value]].
    5. If exported is a Module Record, then
      1. Let internalSpecifier be the ModuleSpecifier Record { [[Type]]: internal, [[Name]]: dep.[[LocalName]] }.
      2. Append the Record { [[Specifier]]: internalSpecifier, [[Module]]: exported } to dep.[[BlockedReferrer]].[[LoadedModules]].
      3. Perform InnerModuleLoading(state, exported, module, internalSpecifier).
      4. If state.[[IsLoading]] is false, return.
    6. Else,
      1. Assert: exported is an ImportedModule Record.
      2. Remove dep from state.[[BlockedInternalImports]].
      3. Append the Record { [[BlockerReferrer]]: module, [[BlockerSpecifier]]: exported.[[Specifier]], [[ImportName]]: exported.[[ImportName]], [[BlockedReferrer]]: dep.[[BlockedReferrer]], [[LocalName]]: dep.[[LocalName]] } to state.[[BlockedInternalImports]].
Editor's Note
TODO: Handle import cycles.

16.2.1.5.1.4 AbortModuleLoading ( state, completion )

The abstract operation AbortModuleLoading takes arguments state (a GraphLoadingState Record) and completion (a normal completion or a throw completion) and returns a Boolean. It performs the following steps when called:

  1. If completion is a normal completion, return false.
  2. Set state.[[IsLoading]] to false.
  3. Perform ! Call(state.[[PromiseCapability]].[[Reject]], undefined, « completion.[[Value]] »).
  4. Return true.

16.2.1.6 Source Text Module Records

In addition to the fields defined in Table 4, Source Text Module Records have the additional fields listed in Table 11. Each of these fields is initially set in ParseModule.

Table 11: Additional Fields of Source Text Module Records
Field Name Value Type Meaning
[[ECMAScriptCode]] a Parse Node
[[Context]] an ECMAScript execution context
[[ImportMeta]] an Object
[[ImportEntries]] a List of ImportEntry Records
[[LocalExportEntries]] a List of ExportEntry Records
[[IndirectExportEntries]] a List of ExportEntry Records
[[StarExportEntries]] a List of ExportEntry Records
[[VisibleModuleDeclarations]] a List of Records with fields [[Name]] (a String) and [[Module]] (a Module Record) All the ModuleDeclaration declarations that are accessible from this module, either defined in this module or in a parent module. It does not contain two different records with the same [[Name]].

An ImportEntry Record is a Record that digests information about a single declarative import. Each ImportEntry Record has the fields defined in Table 12:

Table 12: ImportEntry Record Fields
Field Name Value Type Meaning
[[ModuleRequest]] a Stringa ModuleSpecifier Record String value ofThe ModuleSpecifier Record representing the ModuleSpecifier of the ImportDeclaration.
[[ImportName]] a String or namespace-object The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. The value namespace-object indicates that the import request is for the target module's namespace object.
[[LocalName]] a String The name that is used to locally access the imported value from within the importing module.
Note 1

Table 13 gives examples of ImportEntry records fields used to represent the syntactic import forms:

Table 13 (Informative): Import Forms Mappings to ImportEntry Records
Import Statement Form [[ModuleRequest]] [[ImportName]] [[LocalName]]
import v from "mod"; "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } "default" "v"
import * as ns from "mod"; "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } namespace-object "ns"
import {x} from "mod"; "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } "x" "x"
import {x as v} from "mod"; "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } "x" "v"
import {x as v} from mod; ModuleSpecifier Record { [[Type]]: internal, [[Name]]: "mod" } "x" "v"
import "mod"; An ImportEntry Record is not created.

An ExportEntry Record is a Record that digests information about a single declarative export. Each ExportEntry Record has the fields defined in Table 14:

Table 14: ExportEntry Record Fields
Field Name Value Type Meaning
[[ExportName]] a String or null The name used to export this binding by this module.
[[ModuleRequest]] a StringModuleSpecifier Record or null The String value ofModuleSpecifier Record representing the ModuleSpecifier of the ExportDeclaration. null if the ExportDeclaration does not have a ModuleSpecifier.
[[ImportName]] a String, null, all, or all-but-default The name under which the desired binding is exported by the module identified by [[ModuleRequest]]. null if the ExportDeclaration does not have a ModuleSpecifier. all is used for export * as ns from "mod" declarations. all-but-default is used for export * from "mod" declarations.
[[LocalName]] a String or null The name that is used to locally access the exported value from within the importing module. null if the exported value is not locally accessible from within the module.
Note 2

Table 15 gives examples of the ExportEntry record fields used to represent the syntactic export forms:

Table 15 (Informative): Export Forms Mappings to ExportEntry Records
Export Statement Form [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
export var v; "v" null null "v"
export default function f() {} "default" null null "f"
export default function () {} "default" null null "*default*"
export default 42; "default" null null "*default*"
export {x}; "x" null null "x"
export {v as x}; "x" null null "v"
export {x} from "mod"; "x" "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } "x" null
export {v as x} from "mod"; "x" "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } "v" null
export * from "mod"; null "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } all-but-default null
export * as ns from "mod"; "ns" "mod"ModuleSpecifier Record { [[Type]]: external, [[Name]]: "mod" } all null
export {x} from mod; "x" ModuleSpecifier Record { [[Type]]: internal, [[Name]]: "mod" } "x" null

The following definitions specify the required concrete methods and other abstract operations for Source Text Module Records

16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined )

The abstract operation ParseModule takes arguments sourceText (ECMAScript source text), realm (a Realm Record), and hostDefined (anything) and returns a Source Text Module Record or a non-empty List of SyntaxError objects. It creates a Source Text Module Record based upon the result of parsing sourceText as a Module. It performs the following steps when called:

  1. Let body be ParseText(sourceText, Module).
  2. If body is a List of errors, return body.
  3. Return BuildSourceTextModuleRecord(body, realm, hostDefined, a new empty List).

16.2.1.6.1.1 BuildSourceTextModuleRecord ( body, realm, hostDefined, outerModuleDeclarations )

The abstract operation BuildSourceTextModuleRecord takes arguments body (a Module or ModuleBody Parse Node), realm (a Realm Record), hostDefined (anything), and outerModuleDeclarations (a List of Records with fields [[Name]] (a String) and [[Module]] (a Module Record)) and returns a Source Text Module Record. It creates a Source Text Module Record based upon the result of analysing body. It performs the following steps when called:

  1. Let requestedModules be the ModuleRequests of body.
  2. Let importEntries be ImportEntries of body.
  3. Let importedBoundNames be ImportedLocalNames(importEntries).
  4. Let indirectExportEntries be a new empty List.
  5. Let localExportEntries be a new empty List.
  6. Let starExportEntries be a new empty List.
  7. Let exportEntries be ExportEntries of body.
  8. For each ExportEntry Record ee of exportEntries, do
    1. If ee.[[ModuleRequest]] is null, then
      1. If ee.[[LocalName]] is not an element of importedBoundNames, then
        1. Append ee to localExportEntries.
      2. Else,
        1. Let ie be the element of importEntries whose [[LocalName]] is the same as ee.[[LocalName]].
        2. If ie.[[ImportName]] is namespace-object, then
          1. NOTE: This is a re-export of an imported module namespace object.
          2. Append ee to localExportEntries.
        3. Else,
          1. NOTE: This is a re-export of a single name.
          2. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } to indirectExportEntries.
    2. Else if ee.[[ImportName]] is all-but-default, then
      1. Assert: ee.[[ExportName]] is null.
      2. Append ee to starExportEntries.
    3. Else,
      1. Append ee to indirectExportEntries.
  9. Let async be body Contains await.
  10. Let visibleModuleDeclarations be InstantiateModuleDeclarations(body, realm, hostDefined, outerModuleDeclarations).
  11. Append each element of outerModuleDeclarations to visibleModuleDeclarations.
  12. Return Source Text Module Record { [[Realm]]: realm, [[Environment]]: empty, [[Namespace]]: empty, [[CycleRoot]]: empty, [[HasTLA]]: async, [[AsyncEvaluation]]: false, [[TopLevelCapability]]: empty, [[AsyncParentModules]]: « », [[PendingAsyncDependencies]]: empty, [[Status]]: new, [[EvaluationError]]: empty, [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[ImportMeta]]: empty, [[RequestedModules]]: requestedModules, [[LoadedModules]]: a new empty List, [[VisibleModuleDeclarations]]: visibleModuleDeclarations, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: empty, [[DFSAncestorIndex]]: empty }.

16.2.1.6.1.2 InstantiateModuleDeclarations ( node, realm, hostDefined, outerModuleDeclarations )

The abstract operation InstantiateModuleDeclarations takes arguments node (a Parse Node), realm (a Realm Record), hostDefined (anything), and outerModuleDeclarations (a List of Records with fields [[Name]] (a String) and [[Module]] (a Module Record)) and returns a List of Records with fields [[Name]] (a String) and [[Module]] (a Source Text Module Record). It creates the Module Records corresponding to the ModuleDeclarations directly contained within node. It performs the following steps when called:

  1. Let localModuleDeclarations be a new empty List.
  2. Let visibleModuleDeclarations be a new empty List.
  3. Let topLevelModuleDeclarations be the TopLevelModuleDeclarations of node.
  4. For each Parse Node decl of topLevelModuleDeclarations, do
    1. Let name be the sole element of the BoundNames of decl.
    2. Let rec be the Record { [[Name]]: name, [[Module]]: empty }.
    3. Append rec to visibleModuleDeclarations.
    4. Append rec to localModuleDeclarations.
    5. NOTE: The [[Module]] field of this Record will be set to a Module Record before the end of this ParseModule operation. The empty value is never observable outside of ParseModule.
  5. If outerModuleDeclarations is not empty, then
    1. Let localDeclaredNames be the list-concatenation of the VarDeclaredNames of node and the LexicallyDeclaredNames of node.
    2. For each Record m of outerModuleDeclarations, do
      1. If m.[[Name]] is not an element of localDeclaredNames and visibleModuleDeclarations does not contain a Record with [[Name]] equal to m.[[Name]], then
        1. Append m to visibleModuleDeclarations.
    3. TODO: Instead of copying all of them, we could just add the declarations that are imported inside this module. This would simplify structured cloning, since we wouldn't need to clone all the visible modules.
  6. For each Parse Node decl of topLevelModuleDeclarations, do
    1. Let name be the sole element of the BoundNames of decl.
    2. Let rec be the Record in localModuleDeclarations with [[Name]] equal to name.
    3. Assert: rec exists and is unique.
    4. Let moduleRecord be BuildSourceTextModuleRecord(decl's ModuleBody, realm, hostDefined, visibleModuleDeclarations).
    5. Set rec.[[Module]] to moduleRecord.
  7. Return localModuleDeclarations.

16.2.1.6.4 InitializeEnvironment ( )

The InitializeEnvironment concrete method of a Source Text Module Record module takes no arguments and returns either a normal completion containing unused or a throw completion. It performs the following steps when called:

  1. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
    1. Let resolution be ? module.ResolveExport(e.[[ExportName]]).
    2. If resolution is null or ambiguous, throw a SyntaxError exception.
    3. Assert: resolution is a ResolvedBinding Record.
  2. Assert: All named exports from module are resolvable.
  3. Let realm be module.[[Realm]].
  4. Assert: realm is not undefined.
  5. Let env be NewModuleEnvironment(realm.[[GlobalEnv]]).
  6. Set module.[[Environment]] to env.
  7. For each ImportEntry Record in of module.[[ImportEntries]], do
    1. Let importedModule be GetImportedModule(module, in.[[ModuleSpecifier]]).
    2. Assert: importedModule is not empty, because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.
    3. If in.[[ImportName]] is namespace-object, then
      1. Let namespace be GetModuleNamespace(importedModule).
      2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
      3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
    4. Else,
      1. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]]).
      2. If resolution is null or ambiguous, throw a SyntaxError exception.
      3. If resolution.[[BindingName]] is namespace, then
        1. Let namespace be GetModuleNamespace(resolution.[[Module]]).
        2. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
        3. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
      4. Else,
        1. Perform env.CreateImportBinding(in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
  8. Let moduleContext be a new ECMAScript code execution context.
  9. Set the Function of moduleContext to null.
  10. Assert: module.[[Realm]] is not undefined.
  11. Set the Realm of moduleContext to module.[[Realm]].
  12. Set the ScriptOrModule of moduleContext to module.
  13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
  14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
  15. Set the ModuleDeclarationsEnvironment of moduleContext to null.
  16. Set module.[[Context]] to moduleContext.
  17. Push moduleContext onto the execution context stack; moduleContext is now the running execution context.
  18. Let code be module.[[ECMAScriptCode]].
  19. Let varDeclarations be the VarScopedDeclarations of code.
  20. Let declaredVarNames be a new empty List.
  21. For each element d of varDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If dn is not an element of declaredVarNames, then
        1. Perform ! env.CreateMutableBinding(dn, false).
        2. Perform ! env.InitializeBinding(dn, undefined).
        3. Append dn to declaredVarNames.
  22. Let lexDeclarations be the LexicallyScopedDeclarations of code.
  23. Let privateEnv be null.
  24. For each element d of lexDeclarations, do
    1. For each element dn of the BoundNames of d, do
      1. If IsConstantDeclaration of d is true, then
        1. Perform ! env.CreateImmutableBinding(dn, true).
      2. Else,
        1. Perform ! env.CreateMutableBinding(dn, false).
      3. If d is a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration, then
        1. Let fo be InstantiateFunctionObject of d with arguments env and privateEnv.
        2. Perform ! env.InitializeBinding(dn, fo).
  25. For each Record m in m.[[VisibleModuleDeclarations]], do
    1. TODO: m.[[VisibleModuleDeclarations]] doesn't contain module declarations imported from other files, but they should all be included.
    2. Perform AddModuleDeclaration(m.[[Name]], _m.[[Module]], env).
    3. Let mo be GetModuleObject(m.[[Module]]).
    4. Perform ! env.InitializeBinding(m.[[Name]], mo).
  26. Remove moduleContext from the execution context stack.
  27. Return unused.

16.2.1.6.6 LoadInternalModule ( name )

The LoadInternalModule concrete method of a Source Text Module Record module takes argument name (a String) and returns a throw completion, or a normal completion containing either a Module Record or a ImportedModule Record. It performs the following steps when called:

  1. For each ImportEntry Record entry of module.[[ImportEntries]], do
    1. If entry.[[LocalName]] is name, then
      1. If entry.[[ImportName]] is namespace-object, throw a TypeError exception.
      2. Return the ImportedModule Record { [[Specifier]]: entry.[[ModuleRequest]], [[ImportName]]: entry.[[ImportName]] }.
  2. For each Record r of module.[[VisibleModuleDeclarations]], do
    1. If r.[[Name]] is equal to name, then
      1. Return r.[[Module]].
  3. Throw a new TypeError exception.

16.2.1.6.7 GetExportedModule ( name )

The GetExportedModule concrete method of a Source Text Module Record module takes argument name (a String) and returns a throw completion, or a normal completion containing either a Module Record or a ImportedModule Record. It performs the following steps when called:

  1. For each ExportEntries Record entry of module.[[LocalExportEntries]], do
    1. If entry.[[ExportName]] is name, then
      1. If entry.[[ModuleRequest]] is null, then
        1. Assert: entry.[[LocalName]] is a String.
        2. For each Record decl of module.[[VisibleModuleDeclarations]], do
          1. If decl.[[Name]] is entry.[[LocalName]], then
            1. Return decl.[[Module]].
        3. Throw a new TypeError exception.
      2. Else if entry.[[ImportName]] is all-but-default, then
        1. Throw a new TypeError exception.
      3. Else if entry.[[ImportName]] is all, then
        1. TODO: Study how we can support this case, if needed.
        2. Throw a new TypeError exception.
      4. Else,
        1. Assert: entry.[[ImportName]] is a String.
        2. Return the ImportedModule Record { [[Specifier]]: entry.[[ModuleRequest]], [[ImportName]]: entry.[[ImportName]] }.

16.2.1.8 FinishLoadingImportedModule ( referrer, specifier, payload, result )

The abstract operation FinishLoadingImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or a Realm Record), specifier (a String), payload (a GraphLoadingState Record or a PromiseCapability Record), and result (either a normal completion containing a Module Record or a throw completion) and returns unused. It performs the following steps when called:

  1. Let specifierRecord be the ModuleSpecifier Record { [[Name]]: specifier, [[Type]]: external }.
  2. If result is a normal completion, then
    1. If referrer.[[LoadedModules]] contains a Record record such that record.[[Specifier]] is specifierspecifierRecord, then
      1. Assert: record.[[Module]] is result.[[Value]].
    2. Else, append the Record { [[Specifier]]: specifierspecifierRecord, [[Module]]: result.[[Value]] } to referrer.[[LoadedModules]].
  3. If payload is a GraphLoadingState Record, then
    1. Perform ContinueModuleLoading(payload, referrer, specifierRecord, result).
  4. Else,
    1. Perform ContinueDynamicImport(payload, result).

16.2.2 Imports

Syntax

ImportDeclaration : import ImportClause FromClause ; import ModuleSpecifier ; FromClause : from ModuleSpecifier ModuleSpecifier : StringLiteral Identifier

16.2.2.3 Static Semantics: ImportEntriesForModule

The syntax-directed operation ImportEntriesForModule takes argument module (a StringModuleSpecifier Record) and returns a List of ImportEntry Records.

16.2.3 Exports

Syntax

ExportDeclaration : export ExportFromClause FromClause ; export NamedExports ; export VariableStatement[~Yield, +Await] export Declaration[~Yield, +Await] export default HoistableDeclaration[~Yield, +Await, +Default] export default ClassDeclaration[~Yield, +Await, +Default] export default ModuleDeclaration[+Default] export default [lookahead ∉ { function, async [no LineTerminator here] function, class, module [no LineTerminator here] { }] AssignmentExpression[+In, ~Yield, +Await] ;

16.2.3.1 Static Semantics: ExportEntriesForModule

The syntax-directed operation ExportEntriesForModule takes argument module (a StringModuleSpecifier Record or null) and returns a List of ExportEntry Records.

A Copyright & Software License

Copyright Notice

© 2023 Daniel Ehrenberg, Nicolò Ribaudo

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.