diff --git a/test/language/export/export-defer/load-and-evaluation/chained-defer/chained-defer.js b/test/language/export/export-defer/load-and-evaluation/chained-defer/chained-defer.js new file mode 100644 index 00000000000..c9e0399eb0d --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/chained-defer/chained-defer.js @@ -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']); diff --git a/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-a_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-a_FIXTURE.js new file mode 100644 index 00000000000..e69843aa18f --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-a_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-b_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-b_FIXTURE.js new file mode 100644 index 00000000000..752f854b57d --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-b_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-c_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-c_FIXTURE.js new file mode 100644 index 00000000000..0c25ce1900e --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/chained-defer/dep-c_FIXTURE.js @@ -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'; diff --git a/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/barrel_FIXTURE.js new file mode 100644 index 00000000000..4c4186c9495 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/barrel_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/consumer-imports-loads.js b/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/consumer-imports-loads.js new file mode 100644 index 00000000000..9e404b4ab28 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/consumer-imports-loads/consumer-imports-loads.js @@ -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']); diff --git a/test/language/export/export-defer/load-and-evaluation/dep-syntax-error_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/dep-syntax-error_FIXTURE.js new file mode 100644 index 00000000000..faaa89ace42 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/dep-syntax-error_FIXTURE.js @@ -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! diff --git a/test/language/export/export-defer/load-and-evaluation/dep_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/dep_FIXTURE.js new file mode 100644 index 00000000000..b1a440b2791 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/dep_FIXTURE.js @@ -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; diff --git a/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/barrel_FIXTURE.js new file mode 100644 index 00000000000..b8a41b91832 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/barrel_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/no-consumer-no-load.js b/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/no-consumer-no-load.js new file mode 100644 index 00000000000..9854eed7246 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/no-consumer-no-load/no-consumer-no-load.js @@ -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'); diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/barrel_FIXTURE.js new file mode 100644 index 00000000000..4c4186c9495 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/barrel_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/consumer_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/consumer_FIXTURE.js new file mode 100644 index 00000000000..684b363535c --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/consumer_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/reexport-non-defer-consumed.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/reexport-non-defer-consumed.js new file mode 100644 index 00000000000..faf392da4a6 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-consumed/reexport-non-defer-consumed.js @@ -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']); diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/barrel_FIXTURE.js new file mode 100644 index 00000000000..4c4186c9495 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/barrel_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/consumer_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/consumer_FIXTURE.js new file mode 100644 index 00000000000..684b363535c --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/consumer_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/reexport-non-defer-unconsumed.js b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/reexport-non-defer-unconsumed.js new file mode 100644 index 00000000000..46dbf5909ee --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/reexport-non-defer-unconsumed/reexport-non-defer-unconsumed.js @@ -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']); diff --git a/test/language/export/export-defer/load-and-evaluation/setup_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/setup_FIXTURE.js new file mode 100644 index 00000000000..c72aabeac21 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/setup_FIXTURE.js @@ -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 = []; diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-default/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/barrel_FIXTURE.js new file mode 100644 index 00000000000..e891572389a --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/barrel_FIXTURE.js @@ -0,0 +1,7 @@ +// 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 var marker = 'barrel-loaded'; +export defer { foo as default } from "../dep-syntax-error_FIXTURE.js"; diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-default/consumer_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/consumer_FIXTURE.js new file mode 100644 index 00000000000..27c57477aaf --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/consumer_FIXTURE.js @@ -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 * from "./barrel_FIXTURE.js"; diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-default/star-reexport-default.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/star-reexport-default.js new file mode 100644 index 00000000000..c5851cb62fe --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-default/star-reexport-default.js @@ -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-moduledeclarationlinking +description: > + `export * from` over a module with a deferred default re-export does NOT + pull the deferred source. `export *` is ALL-BUT-DEFAULT, so the deferred + default is filtered out of the consumer's optional indirect requests and + its source module is never linked. +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_). + + `export * from barrel` produces a request for barrel with + [[ImportedNames]] = ~all-but-default~. When BuildLinkingList recurses + through consumer into barrel, GetNewOptionalIndirectExportsModuleRequests + filters barrel's deferred re-exports by this name set. Barrel's only + deferred re-export (`export defer { foo as default } from ...`) is named + `default`, which ~all-but-default~ excludes — so the deferred source is + dropped from the linking list. + + The dep has a SyntaxError. If it were loaded, a resolution-phase + SyntaxError would be thrown. The test runs to completion; asserting + that `marker` surfaces through consumer's `export *` and that both + barrel and consumer ran proves the star re-export mechanism executed + and correctly filtered out the deferred default. +flags: [module] +features: [export-defer] +includes: [compareArray.js] +---*/ + +import "../setup_FIXTURE.js"; +import { marker } from "./consumer_FIXTURE.js"; + +assert.sameValue(marker, 'barrel-loaded'); +assert.compareArray(globalThis.evaluations, ['barrel', 'consumer']); diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/barrel_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/barrel_FIXTURE.js new file mode 100644 index 00000000000..4c4186c9495 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/barrel_FIXTURE.js @@ -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"; diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/consumer_FIXTURE.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/consumer_FIXTURE.js new file mode 100644 index 00000000000..27c57477aaf --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/consumer_FIXTURE.js @@ -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 * from "./barrel_FIXTURE.js"; diff --git a/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/star-reexport-non-default.js b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/star-reexport-non-default.js new file mode 100644 index 00000000000..31a46c38fd4 --- /dev/null +++ b/test/language/export/export-defer/load-and-evaluation/star-reexport-non-default/star-reexport-non-default.js @@ -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: > + `export * from` over a module with a deferred non-default re-export + pulls the deferred source into the evaluation list. 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. + `export *` (ALL-BUT-DEFAULT) exposes non-default bindings through the + star re-export, so barrel's deferred non-default x surfaces in consumer's + optional indirect exports. BuildEvaluationList appends barrel first, then + barrel's deferred dep, 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']);