Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-moduleevaluation
description: >
A chain of deferred re-exports A -> B -> C evaluates all three modules when
the consumer imports x. Each deferred source evaluates after its
re-exporter, producing the order [a, b, c].
info: |
1. Evaluate ( [ _importedNames_ ] )
1. ...
1. Else,
1. ...
1. Let _result_ be Completion(InnerModuleEvaluation(_module_, _stack_, 0)).
1. ...
1. ...
1. Let _optionalIndirectRequests_ be _module_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Let _promises_ be « _topLevelPromise_ ».
1. For each ModuleRequest Record _request_ of _optionalIndirectRequests_, do
1. ...
1. Let _innerPromise_ be _requiredModule_.Evaluate(_request_.[[ImportedNames]]).
1. ...
1. Append _innerPromise_ to _promises_.
1. If _promises_ contains a Promise _P_ such that _P_.[[PromiseState]] is ~pending~, then
1. ...
1. Return ! SafePerformPromiseAll(...).

1. InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be « ».
1. Perform BuildEvaluationList(_evaluationList_, _module_, _module_.[[RequestedModules]]).

1. BuildEvaluationList ( _evaluationList_, _referrer_, _moduleRequests_ )
1. For each ModuleRequest Record _request_ of _moduleRequests_, do
1. Let _requiredModule_ be GetImportedModule(_referrer_, _request_.[[Specifier]]).
1. If _request_.[[Phase]] is ~defer~, then
1. Perform ListAppendUnique(_evaluationList_, GatherAsynchronousTransitiveDependencies(_requiredModule_)).
1. Else if _evaluationList_ does not contain _requiredModule_, then
1. Append _requiredModule_ to _evaluationList_.
1. If _requiredModule_ is a Cyclic Module Record, then
1. Let _importedNames_ be _request_.[[ImportedNames]].
1. ...
1. Else,
1. Let _optionalIndirectRequests_ be _requiredModule_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Perform BuildEvaluationList(_evaluationList_, _requiredModule_, _optionalIndirectRequests_).

Evaluate first runs InnerModuleEvaluation on the top-level module, then
iterates _optionalIndirectRequests_ to evaluate the deferred sources.
BuildEvaluationList appends each re-exporter to _evaluationList_ first,
then recurses into its deferred (optional indirect) exports — so each
deferred source is appended after its re-exporter. For the chain
A -> B -> C, iteration yields A, then B (A's deferred source), then C.
flags: [module]
features: [export-defer]
includes: [compareArray.js]
---*/

import "../setup_FIXTURE.js";
import { x } from "./dep-a_FIXTURE.js";

assert.sameValue(x, 'c-value');
assert.compareArray(globalThis.evaluations, ['a', 'b', 'c']);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('a');

export defer { x } from "./dep-b_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('b');

export defer { x } from "./dep-c_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('c');

export var x = 'c-value';
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('barrel');

export defer { x } from "../dep_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-moduleevaluation
description: >
`export defer { x } from "./dep.js"` loads and evaluates dep.js when a
consumer imports x. The deferred source evaluates after the re-exporter.
info: |
1. Evaluate ( [ _importedNames_ ] )
1. ...
1. Else,
1. ...
1. Let _result_ be Completion(InnerModuleEvaluation(_module_, _stack_, 0)).
1. ...
1. ...
1. Let _optionalIndirectRequests_ be _module_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Let _promises_ be « _topLevelPromise_ ».
1. For each ModuleRequest Record _request_ of _optionalIndirectRequests_, do
1. ...
1. Let _innerPromise_ be _requiredModule_.Evaluate(_request_.[[ImportedNames]]).
1. ...
1. Append _innerPromise_ to _promises_.
1. If _promises_ contains a Promise _P_ such that _P_.[[PromiseState]] is ~pending~, then
1. ...
1. Return ! SafePerformPromiseAll(...).

1. InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be « ».
1. Perform BuildEvaluationList(_evaluationList_, _module_, _module_.[[RequestedModules]]).

1. BuildEvaluationList ( _evaluationList_, _referrer_, _moduleRequests_ )
1. For each ModuleRequest Record _request_ of _moduleRequests_, do
1. Let _requiredModule_ be GetImportedModule(_referrer_, _request_.[[Specifier]]).
1. If _request_.[[Phase]] is ~defer~, then
1. Perform ListAppendUnique(_evaluationList_, GatherAsynchronousTransitiveDependencies(_requiredModule_)).
1. Else if _evaluationList_ does not contain _requiredModule_, then
1. Append _requiredModule_ to _evaluationList_.
1. If _requiredModule_ is a Cyclic Module Record, then
1. Let _importedNames_ be _request_.[[ImportedNames]].
1. ...
1. Else,
1. Let _optionalIndirectRequests_ be _requiredModule_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Perform BuildEvaluationList(_evaluationList_, _requiredModule_, _optionalIndirectRequests_).

Evaluate first runs InnerModuleEvaluation on the top-level module,
evaluating it and its non-deferred dependencies, and only afterwards
iterates _optionalIndirectRequests_ to evaluate the deferred re-export
sources. BuildEvaluationList appends the re-exporter to _evaluationList_
first, then recurses into its deferred (optional indirect) exports —
appending them after the re-exporter itself.
flags: [module]
features: [export-defer]
includes: [compareArray.js]
---*/

import "../setup_FIXTURE.js";
import { x } from "./barrel_FIXTURE.js";

assert.sameValue(x, 42);
assert.compareArray(globalThis.evaluations, ['barrel', 'dep']);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

invalid syntax!
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('dep');

export var x = 42;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

export var marker = 'loaded';
export defer { x } from "../dep-syntax-error_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-moduledeclarationlinking
description: >
`export defer { x } from "./dep.js"` does not load dep.js when no consumer
imports x. The deferred binding's name is absent from any caller's
importedNames, so the source module's linking is skipped.
info: |
1. Link ( [ _importedNames_ ] )
1. ...
1. If _importedNames_ is not present, let _importedNames_ be ~all~.
1. ...
1. Let _result_ be Completion(InnerModuleLinking(_module_, _stack_, 0)).
1. ...
1. Let _optionalIndirectRequests_ be _module_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. For each ModuleRequest Record _request_ of _optionalIndirectRequests_, do
1. Let _requiredModule_ be GetImportedModule(_module_, _request_).
1. ...
1. If _requiredModule_.[[Status]] is ~unlinked~, perform ? _requiredModule_.Link(_request_.[[ImportedNames]]).

1. InnerModuleLinking ( _module_, _stack_, _index_ )
1. ...
1. Let _linkingList_ be « ».
1. Perform BuildLinkingList(_linkingList_, _module_, _module_.[[RequestedModules]], « »).
1. For each Module Record _requiredModule_ of _linkingList_, do
1. Set _index_ to ? InnerModuleLinking(_requiredModule_, _stack_, _index_).
1. ...

1. BuildLinkingList ( _linkingList_, _referrer_, _moduleRequests_, _previouslyImportedNames_ )
1. For each ModuleRequest Record _request_ of _moduleRequests_, do
1. Let _requiredModule_ be GetImportedModule(_referrer_, _request_).
1. If _linkingList_ does not contain _requiredModule_, then
1. Append _requiredModule_ to _linkingList_.
1. ...
1. If _requiredModule_ is a Cyclic Module Record, then
1. Let _optionalIndirectRequests_ be GetNewOptionalIndirectExportsModuleRequests(_requiredModule_, _request_.[[ImportedNames]], _previouslyImportedNames_).
1. Perform BuildLinkingList(_linkingList_, _requiredModule_, _optionalIndirectRequests_, _previouslyImportedNames_).

An optional indirect (deferred) re-export is only linked when the
re-exported binding's name is present in the consumer's imported names.
GetNewOptionalIndirectExportsModuleRequests filters the deferred
re-exports by _request_.[[ImportedNames]]; deferred re-exports whose
names are not requested are skipped, and their source modules never
enter the linking list.

If dep-syntax-error_FIXTURE.js were loaded, a resolution-phase
SyntaxError would be thrown. The test runs to completion, proving it
was not loaded. Barrel's `marker` export is asserted to confirm the
barrel itself did load, ruling out the degenerate "nothing ran" case.
flags: [module]
features: [export-defer]
---*/

import { marker } from "./barrel_FIXTURE.js";

assert.sameValue(marker, 'loaded');
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('barrel');

export defer { x } from "../dep_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('consumer');

export { x } from "./barrel_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-moduleevaluation
description: >
A plain (non-defer) re-export of a binding from a module that defers it
forces the source to be loaded. When the entrypoint consumes x, barrel
evaluates first, then its deferred dep, and consumer evaluates last.
info: |
1. Evaluate ( [ _importedNames_ ] )
1. ...
1. Else,
1. ...
1. Let _result_ be Completion(InnerModuleEvaluation(_module_, _stack_, 0)).
1. ...
1. ...
1. Let _optionalIndirectRequests_ be _module_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Let _promises_ be « _topLevelPromise_ ».
1. For each ModuleRequest Record _request_ of _optionalIndirectRequests_, do
1. ...
1. Let _innerPromise_ be _requiredModule_.Evaluate(_request_.[[ImportedNames]]).
1. ...
1. Append _innerPromise_ to _promises_.
1. If _promises_ contains a Promise _P_ such that _P_.[[PromiseState]] is ~pending~, then
1. ...
1. Return ! SafePerformPromiseAll(...).

1. InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be « ».
1. Perform BuildEvaluationList(_evaluationList_, _module_, _module_.[[RequestedModules]]).

1. BuildEvaluationList ( _evaluationList_, _referrer_, _moduleRequests_ )
1. For each ModuleRequest Record _request_ of _moduleRequests_, do
1. Let _requiredModule_ be GetImportedModule(_referrer_, _request_.[[Specifier]]).
1. If _request_.[[Phase]] is ~defer~, then
1. Perform ListAppendUnique(_evaluationList_, GatherAsynchronousTransitiveDependencies(_requiredModule_)).
1. Else if _evaluationList_ does not contain _requiredModule_, then
1. Append _requiredModule_ to _evaluationList_.
1. If _requiredModule_ is a Cyclic Module Record, then
1. Let _importedNames_ be _request_.[[ImportedNames]].
1. ...
1. Else,
1. Let _optionalIndirectRequests_ be _requiredModule_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Perform BuildEvaluationList(_evaluationList_, _requiredModule_, _optionalIndirectRequests_).

Evaluate first runs InnerModuleEvaluation on the top-level module,
evaluating its non-deferred dependencies, and only afterwards iterates
_optionalIndirectRequests_ to evaluate the deferred sources. Consumer's
plain `export { x } from barrel` makes barrel a non-defer dependency of
consumer; barrel evaluates first, then barrel's deferred dep evaluates
(appended after barrel in BuildEvaluationList via its optional indirect
exports), and consumer — which depends on both — evaluates last.
flags: [module]
features: [export-defer]
includes: [compareArray.js]
---*/

import "../setup_FIXTURE.js";
import { x } from "./consumer_FIXTURE.js";

assert.sameValue(x, 42);
assert.compareArray(globalThis.evaluations, ['barrel', 'dep', 'consumer']);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('barrel');

export defer { x } from "../dep_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations.push('consumer');

export { x } from "./barrel_FIXTURE.js";
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
esid: sec-moduleevaluation
description: >
A plain (non-defer) re-export of a deferred binding forces the source
module to load and evaluate even when the entrypoint never consumes the
binding. Barrel evaluates first, then its deferred dep, and consumer
evaluates last.
info: |
1. Evaluate ( [ _importedNames_ ] )
1. ...
1. Else,
1. ...
1. Let _result_ be Completion(InnerModuleEvaluation(_module_, _stack_, 0)).
1. ...
1. ...
1. Let _optionalIndirectRequests_ be _module_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Let _promises_ be « _topLevelPromise_ ».
1. For each ModuleRequest Record _request_ of _optionalIndirectRequests_, do
1. ...
1. Let _innerPromise_ be _requiredModule_.Evaluate(_request_.[[ImportedNames]]).
1. ...
1. Append _innerPromise_ to _promises_.
1. If _promises_ contains a Promise _P_ such that _P_.[[PromiseState]] is ~pending~, then
1. ...
1. Return ! SafePerformPromiseAll(...).

1. InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be « ».
1. Perform BuildEvaluationList(_evaluationList_, _module_, _module_.[[RequestedModules]]).

1. BuildEvaluationList ( _evaluationList_, _referrer_, _moduleRequests_ )
1. For each ModuleRequest Record _request_ of _moduleRequests_, do
1. Let _requiredModule_ be GetImportedModule(_referrer_, _request_.[[Specifier]]).
1. If _request_.[[Phase]] is ~defer~, then
1. Perform ListAppendUnique(_evaluationList_, GatherAsynchronousTransitiveDependencies(_requiredModule_)).
1. Else if _evaluationList_ does not contain _requiredModule_, then
1. Append _requiredModule_ to _evaluationList_.
1. If _requiredModule_ is a Cyclic Module Record, then
1. Let _importedNames_ be _request_.[[ImportedNames]].
1. ...
1. Else,
1. Let _optionalIndirectRequests_ be _requiredModule_.GetOptionalIndirectExportsModuleRequests(_importedNames_).
1. Perform BuildEvaluationList(_evaluationList_, _requiredModule_, _optionalIndirectRequests_).

Evaluate first runs InnerModuleEvaluation on the top-level module, then
iterates _optionalIndirectRequests_ to evaluate the deferred sources.
Consumer's plain `export { x } from barrel` makes barrel a non-defer
dependency of consumer regardless of whether the entrypoint consumes x.
BuildEvaluationList appends barrel first, then barrel's deferred dep via
its optional indirect exports, and consumer — which depends on both —
evaluates last.
flags: [module]
features: [export-defer]
includes: [compareArray.js]
---*/

import "../setup_FIXTURE.js";
import "./consumer_FIXTURE.js";

assert.compareArray(globalThis.evaluations, ['barrel', 'dep', 'consumer']);
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

globalThis.evaluations = [];
Loading
Loading