Add partial tests for `import defer` (#4278)

Co-authored-by: Asumu Takikawa <asumu@igalia.com>
This commit is contained in:
Nicolò Ribaudo 2024-12-02 10:32:38 +01:00 committed by GitHub
parent 80d32d1a47
commit 10c2615aa5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
82 changed files with 1728 additions and 0 deletions

View File

@ -84,6 +84,10 @@ Atomics.pause
# https://github.com/tc39/proposal-is-error
Error.isError
# Deferred import evaluation
# https://tc39.es/proposal-defer-import-eval
import-defer
## Standard language features
#
# Language features that have been included in a published version of the

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as depDeferredNamespace from "./dep_FIXTURE.js";
export { depDeferredNamespace };

View File

@ -0,0 +1,5 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
export const foo = 1;
export const bar = 2;

View File

@ -0,0 +1,52 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-modulenamespacecreate
description: >
Deferred namespace objects have the correct MOP implementation
info: |
ModuleNamespaceCreate ( _module_, _exports_, _phase_ )
1. Let _internalSlotsList_ be the internal slots listed in <emu-xref href="#table-internal-slots-of-module-namespace-exotic-objects"></emu-xref>.
1. Let _M_ be MakeBasicObject(_internalSlotsList_).
1. Set _M_'s essential internal methods to the definitions specified in <emu-xref href="#sec-module-namespace-exotic-objects"></emu-xref>.
1. ...
[[GetPrototypeOf]] ( )
1. Return null.
[[IsExtensible]] ( )
1. Return false.
flags: [module]
features: [import-defer]
includes: [propertyHelper.js, compareArray.js]
---*/
import defer * as ns from "./dep_FIXTURE.js";
assert.sameValue(typeof ns, "object", "Deferred namespaces are objects");
assert(!Reflect.isExtensible(ns), "Deferred namespaces are not extensible");
assert.sameValue(Reflect.preventExtensions(ns), true, "Deferred namespaces can made non-extensible");
assert.sameValue(Reflect.getPrototypeOf(ns), null, "Deferred namespaces have a null prototype");
assert.sameValue(Reflect.setPrototypeOf(ns, {}), false, "Deferred namespaces' prototype cannot be changed");
assert.sameValue(Reflect.setPrototypeOf(ns, null), true, "Deferred namespaces' prototype can be 'set' to null");
assert.throws(TypeError, () => Reflect.apply(ns, null, []), "Deferred namespaces are not callable");
assert.throws(TypeError, () => Reflect.construct(ns, [], ns), "Deferred namespaces are not constructable");
assert.compareArray(
Reflect.ownKeys(ns),
["bar", "foo", Symbol.toStringTag],
"Deferred namespaces' keys are the exports sorted alphabetically, followed by @@toStringTag"
);
verifyProperty(ns, "foo", {
value: 1,
writable: true,
enumerable: true,
configurable: false,
});
assert.sameValue(Reflect.getOwnPropertyDescriptor(ns, "non-existent"), undefined, "No descriptors for non-exports");

View File

@ -0,0 +1,43 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-getmodulenamespace
description: >
Deferred namespace objects are created and cached appropriately
info: |
GetModuleNamespace ( _module_, _phase_ )
1. ...
1. If _phase_ is ~defer~, let _namespace_ be _module_.[[DeferredNamespace]], otherwise let _namespace_ be _module_.[[Namespace]].
1. If _namespace_ is ~empty~, then
1. ...
1. Set _namespace_ to ModuleNamespaceCreate(_module_, _unambiguousNames_, _phase_).
1. Return _namespace_.
ModuleNamespaceCreate ( _module_, _exports_, _phase_ )
1. ...
1. Let _M_ be MakeBasicObject(_internalSlotsList_).
1. ...
1. If _phase_ is ~defer~, then
1. Set _module_.[[DeferredNamespace]] to _M_.
1. ...
1. Else,
1. Set _module_.[[Namespace]] to _M_.
1. ...
1. Return _M_.
flags: [module]
features: [import-defer]
---*/
import * as nsEager from "./dep_FIXTURE.js";
import defer * as nsDeferred1 from "./dep_FIXTURE.js";
import defer * as nsDeferred2 from "./dep_FIXTURE.js";
import { depDeferredNamespace as nsDeferred3 } from "./dep-defer-ns_FIXTURE.js";
const nsDeferred4 = await import.defer("./dep_FIXTURE.js");
assert.sameValue(nsDeferred1, nsDeferred2, "Deferred import of the same module twice gives the same object");
assert.sameValue(nsDeferred1, nsDeferred3, "Deferred import of the same module twice from different files gives the same object");
assert.sameValue(nsDeferred1, nsDeferred4, "Static and dynamic deferred import of the same module gives the same object");
assert.notSameValue(nsDeferred1, nsEager, "Deferred namespaces are distinct from eager namespaces");

View File

@ -0,0 +1,13 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { resolveFirst, resolveThird, second } from "./promises_FIXTURE.js";
import "./dep-1.1_FIXTURE.js"
await Promise.resolve();
resolveFirst();
await second;
resolveThird();

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as ns from "./dep-1-tla_FIXTURE.js";
export let foo = 1;

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { first, third, rejectDone, resolveDone, resolveSecond } from "./promises_FIXTURE.js";
import defer * as ns from "./dep-1.1.1_FIXTURE.js";
// dep-1 is now in the ~evaluating~ state
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo while evaluating"] = error;
}
first.then(() => {
// dep-1 is now in the ~evaluating-async~ state
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo while evaluating-async"] = error;
}
resolveSecond();
}).then(() => {
return third.then(() => {
// dep-1 is now in the ~evaluated~ state
let foo = ns.foo;
globalThis["value of ns.foo when evaluated"] = foo;
})
}).then(resolveDone, rejectDone);

View File

@ -0,0 +1,47 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger evaluation of modules that have dependencies in their ~evaluating-async~ phase
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [asyncHelpers.js]
---*/
import { done } from "./promises_FIXTURE.js";
import "./dep-1-tla_FIXTURE.js";
asyncTest(async () => {
await done;
assert(globalThis["error on ns.foo while evaluating"] instanceof TypeError, "ns.foo while evaluating throws a TypeError");
assert(globalThis["error on ns.foo while evaluating-async"] instanceof TypeError, "ns.foo while evaluating-async throws a TypeError");
assert.sameValue(globalThis["value of ns.foo when evaluated"], 1);
});

View File

@ -0,0 +1,14 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
export let resolveDone, rejectDone;
export const done = new Promise((r, j) => (resolveDone = r, rejectDone = j));
export let resolveFirst, rejectFirst;
export const first = new Promise((r, j) => (resolveFirst = r, rejectFirst = j));
export let resolveSecond, rejectSecond;
export const second = new Promise((r, j) => (resolveSecond = r, rejectSecond = j));
export let resolveThird, rejectThird;
export const third = new Promise((r, j) => (resolveThird = r, rejectThird = j));

View File

@ -0,0 +1,14 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as dep2 from "./dep-2_FIXTURE.js";
globalThis.dep3evaluated = false;
try {
dep2.foo;
} catch (error) {
globalThis["evaluating dep2.foo error"] = error;
}
globalThis["evaluating dep2.foo evaluates dep3"] = globalThis.dep3evaluated;

View File

@ -0,0 +1,5 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-3_FIXTURE.js";
import "./main.js";

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.dep3evaluated = true;

View File

@ -0,0 +1,42 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger their own evaluation
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module]
features: [import-defer]
---*/
import "./dep-1_FIXTURE.js";
assert(globalThis["evaluating dep2.foo error"] instanceof TypeError, "evaluating dep2.foo throws a TypeError");
assert(!globalThis["evaluating dep2.foo evaluates dep3"], "evaluating dep2.foo does not evaluate dep3");
assert(!globalThis.dep3evaluated, "dep3 is not evaluated at all");

View File

@ -0,0 +1,15 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { resolveFirst, resolveThird, second } from "./promises_FIXTURE.js";
import "./dep-1.1_FIXTURE.js"
await Promise.resolve();
resolveFirst();
await second;
resolveThird();
export let foo = 1;

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import { first, third, resolveSecond, rejectDone, resolveDone } from "./promises_FIXTURE.js";
import defer * as ns from "./dep-1-tla_FIXTURE.js";
// ns is now in the ~evaluating~ state
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo while evaluating"] = error;
}
first.then(() => {
// ns is now in the ~evaluating-async~ state
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo while evaluating-async"] = error;
}
resolveSecond();
}).then(() => {
return third.then(() => {
// ns is now in the ~evaluated~ state
let foo = ns.foo;
globalThis["value of ns.foo when evaluated"] = foo;
})
}).then(resolveDone, rejectDone);

View File

@ -0,0 +1,47 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger evaluation of modules that are in their ~evaluating-async~ phase
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [asyncHelpers.js]
---*/
import { done } from "./promises_FIXTURE.js";
import "./dep-1-tla_FIXTURE.js";
asyncTest(async () => {
await done;
assert(globalThis["error on ns.foo while evaluating"] instanceof TypeError, "ns.foo while evaluating throws a TypeError");
assert(globalThis["error on ns.foo while evaluating-async"] instanceof TypeError, "ns.foo while evaluating-async throws a TypeError");
assert.sameValue(globalThis["value of ns.foo when evaluated"], 1);
});

View File

@ -0,0 +1,14 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
export let resolveDone, rejectDone;
export const done = new Promise((r, j) => (resolveDone = r, rejectDone = j));
export let resolveFirst, rejectFirst;
export const first = new Promise((r, j) => (resolveFirst = r, rejectFirst = j));
export let resolveSecond, rejectSecond;
export const second = new Promise((r, j) => (resolveSecond = r, rejectSecond = j));
export let resolveThird, rejectThird;
export const third = new Promise((r, j) => (resolveThird = r, rejectThird = j));

View File

@ -0,0 +1,10 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as main from "./main.js";
try {
main.foo;
} catch (error) {
globalThis["error on main.foo"] = error;
}

View File

@ -0,0 +1,40 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Deferred namespaces' properties cannot be accessed on a module that is being evaluated
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module]
features: [import-defer]
---*/
import "./dep_FIXTURE.js";
assert(globalThis["error on main.foo"] instanceof TypeError, "main.foo while evaluating throws a TypeError");

View File

@ -0,0 +1,10 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as ns from "./dep_FIXTURE.js";
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo"] = error;
}

View File

@ -0,0 +1,42 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger their own evaluation
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module]
features: [import-defer]
---*/
import defer * as ns from "./dep_FIXTURE.js";
assert(globalThis["error on ns.foo"] instanceof TypeError, "ns.foo while evaluating throws a TypeError");
ns.foo;

View File

@ -0,0 +1,12 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as ns from "./dep_FIXTURE.js";
await Promise.resolve(0);
try {
ns.foo;
} catch (error) {
globalThis["error on ns.foo"] = error;
}

View File

@ -0,0 +1,49 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger their own evaluation
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. ...
flags: [module, async]
features: [import-defer, top-level-await]
---*/
/*
`./dep_FIXTURE.js` is _not_ deferred, because it contains top-level await. So what is happening in this test is that:
- the deferred module is not actually deferred, so `dep_FIXTURE.js` starts executing and goes in its `evaluating` state
- it has access to a deferred namespace of itself
- once it reaches the `await`, the state changes to `evaluating-async`
- the test tries then to access a property from the deferred namespace while it's `evaluating-async` (which is what this test it testing). It should throw.
- `dep_FIXTURE.js` is done, and becomes `evaluated`
- `main.js` starts evaluating, and the error is already there
- `ns.foo` now works, because `ns` is `evaluated` and not `evaluating-async`
*/
import defer * as ns from "./dep_FIXTURE.js";
assert(globalThis["error on ns.foo"] instanceof TypeError, "ns.foo while evaluating throws a TypeError");
ns.foo;
$DONE();

View File

@ -0,0 +1,40 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Modules cannot try to trigger their own evaluation
info: |
10.4.6.8 [[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation ( _O_ )
1. Assert: _O_.[[Deferred]] is *false*.
1. Let _m_ be _O_.[[Module]].
1. If _m_ is a Cyclic Module Record, _m_.[[Status]] is not ~evaluated~, and ReadyForSyncExecution(_m_) is *false*, throw a *TypeError* exception.
1. ...
ReadyForSyncExecution( _module_, _seen_ )
1. If _seen_ is not provided, let _seen_ be a new empty List.
1. If _seen_ contains _module_, return *true*.
1. Append _module_ to _seen_.
1. If _module_.[[Status]] is ~evaluated~, return *true*.
1. If _module_.[[Status]] is ~evaluating~ or ~evaluating-async~, return *false*.
1. Assert: _module_.[[Status]] is ~linked~.
1. If _module_.[[HasTLA]] is *true*, return *false*.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If ReadyForSyncExecution(_requiredModule_, _seen_) is *false*, then
1. Return *false*.
1. Return *true*.
flags: [module]
features: [import-defer]
---*/
import defer * as self from "./get-self-while-evaluating.js";
assert.throws(TypeError, () => self.foo);

View File

@ -0,0 +1,46 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Module evaluation errors are thrown
info: |
[[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation( _O_ )
1. ...
1. Perform ? EvaluateSync(_m_).
1. ...
EvaluateSync ( _module_ )
1. ...
1. Let _promise_ be ! _module_.Evaluate().
1. Assert: _promise_.[[PromiseState]] is either ~fulfilled~ or ~rejected~.
1. If _promise_.[[PromiseState]] is ~rejected~, then
1. Return ThrowCompletion(_promise_.[[PromiseResult]]).
1. ...
flags: [module, async]
features: [import-defer]
includes: [asyncHelpers.js]
---*/
asyncTest(async () => {
let err1;
await import("./throws_FIXTURE.js").catch((e) => { err1 = e });
assert.sameValue(err1.someError, "the error from throws_FIXTURE");
const { ns } = await import("./import-defer-throws_FIXTURE.js");
let err2;
try { ns.foo } catch (e) { err2 = e };
assert.sameValue(
err1,
err2,
"Evaluation errors are thrown for modules evaluated before getting the deferred namespace"
);
});

View File

@ -0,0 +1,5 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import defer * as ns from "./import-defer-throws_FIXTURE.js";
export { ns };

View File

@ -0,0 +1,46 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Module evaluation errors are thrown
info: |
[[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation( _O_ )
1. ...
1. Perform ? EvaluateSync(_m_).
1. ...
EvaluateSync ( _module_ )
1. ...
1. Let _promise_ be ! _module_.Evaluate().
1. Assert: _promise_.[[PromiseState]] is either ~fulfilled~ or ~rejected~.
1. If _promise_.[[PromiseState]] is ~rejected~, then
1. Return ThrowCompletion(_promise_.[[PromiseResult]]).
1. ...
flags: [module, async]
features: [import-defer]
includes: [asyncHelpers.js]
---*/
import defer * as ns from "./throws_FIXTURE.js";
asyncTest(async () => {
let err1;
await import("./throws_FIXTURE.js").catch((e) => { err1 = e });
assert.sameValue(err1.someError, "the error from throws_FIXTURE");
let err2;
try { ns.foo } catch (e) { err2 = e };
assert.sameValue(
err1,
err2,
"Evaluation errors are thrown for modules evaluated after getting the deferred namespace"
);
});

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
throw { someError: "the error from throws_FIXTURE" }

View File

@ -0,0 +1,38 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Module evaluation errors are thrown
info: |
[[Get]] ( _P_, _Receiver_ )
1. ...
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
EnsureDeferredNamespaceEvaluation( _O_ )
1. ...
1. Perform ? EvaluateSync(_m_).
1. ...
EvaluateSync ( _module_ )
1. ...
1. Let _promise_ be ! _module_.Evaluate().
1. Assert: _promise_.[[PromiseState]] is either ~fulfilled~ or ~rejected~.
1. If _promise_.[[PromiseState]] is ~rejected~, then
1. Return ThrowCompletion(_promise_.[[PromiseResult]]).
1. ...
flags: [module]
features: [import-defer]
---*/
import defer * as ns from "./throws_FIXTURE.js";
let err1, err2;
try { ns.foo } catch (e) { err1 = e };
assert.deepEqual(err1, { someError: "the error from throws_FIXTURE" }, "Evaluation errors are thrown when evaluating");
try { ns.foo } catch (e) { err2 = e };
assert.sameValue(err1, err2, "Evaluation errors are thrown for already evaluated modules");

View File

@ -0,0 +1,22 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Host resolution errors are reported eagerly
info: |
LoadRequestedModules ([ _hostDefined_ ])
- just notice that it does not check if the module is deferred
flags: [module]
features: [import-defer]
negative:
phase: resolution
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer * as ns "./resolution-error_FIXTURE.js";

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./missing.js";

View File

@ -0,0 +1,22 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver-EnsureDeferredNamespaceEvaluation
description: >
Syntax errors in deferred modules are reported eagerly
info: |
LoadRequestedModules ([ _hostDefined_ ])
- just notice that it does not check if the module is deferred
flags: [module]
features: [import-defer]
negative:
phase: resolution
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer * as ns "./syntax-error_FIXTURE.js";

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
invalid syntax!

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push(1.1);

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push(1.2);

View File

@ -0,0 +1,9 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-1.1_FIXTURE.js";
import defer * as ns_1_2 from "./dep-1.2_FIXTURE.js";
globalThis.evaluations.push(1);
export { ns_1_2 };

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push(2);

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver
description: >
[[Get]] of a symbol does not trigger evaluation of the module
info: |
[[Get]] ( _P_, _Receiver_ )
1. If _P_ is a Symbol, then
1. Return ! OrdinaryGet(_O_, _P_, _Receiver_).
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
ns1[Symbol.toStringTag];
ns1[Symbol()];
assert.sameValue(globalThis.evaluations.length, 0, "[[Get]] of a symbol does not trigger evaluation");

View File

@ -0,0 +1,24 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-getprototypeof
description: >
[[GetPrototypeOf]] does not trigger evaluation of the module
info: |
[[GetPrototypeOf]] ( )
1. Return **null**.
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
Object.getPrototypeOf(ns1);
assert.sameValue(globalThis.evaluations.length, 0, "[[GetPrototypeOf]] does not trigger evaluation");

View File

@ -0,0 +1,24 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-isextensible
description: >
[[IsExtensible]] does not trigger evaluation of the module
info: |
[[IsExtensible]] ( )
1. Return **false**.
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
Object.isExtensible(ns1);
assert.sameValue(globalThis.evaluations.length, 0, "[[IsExtensible]] does not trigger evaluation");

View File

@ -0,0 +1,24 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-preventextensions
description: >
[[PreventExtensions]] does not trigger evaluation of the module
info: |
[[PreventExtensions]] ( )
1. Return **true**.
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
Object.preventExtensions(ns1);
assert.sameValue(globalThis.evaluations.length, 0, "[[PreventExtensions]] does not trigger evaluation");

View File

@ -0,0 +1,29 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-set-p-v-receiver
description: >
[[Set]] does not trigger evaluation of the module
info: |
[[Set]] ( _P_, _V_, _Receiver_ )
1. Return **false**.
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
try {
ns1.foo = 2;
} catch {}
try {
ns1.ns_1_2 = 3;
} catch {}
assert.sameValue(globalThis.evaluations.length, 0, "[[Set]] of a symbol does not trigger evaluation");

View File

@ -0,0 +1,25 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-setprototypeof-v
description: >
[[SetPrototypeOf]] does not trigger evaluation of the module
info: |
[[SetPrototypeOf]] ( _V_ )
1. Return ! SetImmutablePrototype(_O_, _V_).
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
Reflect.setPrototypeOf(ns1, null);
Reflect.setPrototypeOf(ns1, {});
assert.sameValue(globalThis.evaluations.length, 0, "[[SetPrototypeOf]] does not trigger evaluation");

View File

@ -0,0 +1,27 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-module-namespace-exotic-objects-get-p-receiver
description: >
[[Get]] of a string triggers evaluation of the module
info: |
[[Get]] ( _P_, _Receiver_ )
1. If _P_ is a Symbol, then
1. Return ! OrdinaryGet(_O_, _P_, _Receiver_).
1. If _O_.[[Deferred]] is **true**, perform ? EnsureDeferredNamespaceEvaluation(_O_).
1. ...
flags: [module]
features: [import-defer]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
ns1.foo;
assert(globalThis.evaluations.length > 0, "[[Get]] of a string triggers evaluation");

View File

@ -0,0 +1,47 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-innermoduleevaluation
description: >
`import defer` by itself does not trigger evaluation of sync modules
info: |
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
flags: [module]
features: [import-defer]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
assert.sameValue(globalThis.evaluations.length, 0, "import defer does not trigger evaluation");
const ns_1_2 = ns1.ns_1_2;
assert.compareArray(globalThis.evaluations, [1.1, 1], "when evaluation is triggered, deferred sub-dependencies are not evaluated");
ns1.ns_1_2;
assert.compareArray(globalThis.evaluations, [1.1, 1], "the module is not re-executed");
ns_1_2.foo;
assert.compareArray(globalThis.evaluations, [1.1, 1, 1.2]);

View File

@ -0,0 +1,51 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-static-semantics-modulerequests
description: >
`import defer` by itself does not trigger evaluation of sync modules
info: |
Static Semantics: ModuleRequests
ModuleItemList : ModuleItemList ModuleItem
1. Let _requests_ be ModuleRequests of ModuleItemList.
1. Let _additionalRequests_ be ModuleRequests of ModuleItem.
1. For each ModuleRequest Record _mr_ of _additionalRequests_, do
1. Let _found_ be false.
1. For each ModuleRequest Record _mr2_ of _requests_, do
1. If _mr_.[[Specifier]] is _mr2_.[[Specifier]] and _mr_.[[Phase]] is _mr2_.[[Phase]], then
1. Assert: _found_ is false.
1. Set _found_ to true.
1. If _found_ is false, then
1. Append _mr_ to _requests_.
1. Return _requests_.
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
flags: [module]
features: [import-defer]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import defer * as ns1 from "./dep-1_FIXTURE.js";
import "./dep-2_FIXTURE.js";
import "./dep-1_FIXTURE.js";
assert.compareArray(globalThis.evaluations, [2, 1.1, 1], "the module is evaluated in the order where it's imported as non-deferred");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations = [];

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("1");

View File

@ -0,0 +1,8 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("2.1.1 start");
await Promise.resolve(0);
globalThis.evaluations.push("2.1.1 end");

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-2.1.1-tla_FIXTURE.js";
globalThis.evaluations.push("2.1");

View File

@ -0,0 +1,10 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-2.2.1_FIXTURE.js"
globalThis.evaluations.push("2.2 start");
await Promise.resolve(0);
globalThis.evaluations.push("2.2 end");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("2.2.1");

View File

@ -0,0 +1,7 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-2.1_FIXTURE.js";
import "./dep-2.2-tla_FIXTURE.js";
globalThis.evaluations.push("2");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("3");

View File

@ -0,0 +1,10 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-2.2-tla_FIXTURE.js";
globalThis.evaluations.push("4.1 start");
await Promise.resolve(0);
globalThis.evaluations.push("4.1 end");

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep-4.1-tla_FIXTURE.js";
globalThis.evaluations.push("4");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("5");

View File

@ -0,0 +1,78 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-innermoduleevaluation
description: >
Async dependencies of deferred modules are executed in the right order
info: |
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
GatherAsynchronousTransitiveDependencies ( _module_, [ _seen_ ] )
1. If _seen_ is not specified, let _seen_ be a new empty List.
1. Let _result_ be a new empty List.
1. If _seen_ contains _module_, return _result_.
1. Append _module_ to _seen_.
1. If _module_ is not a Cyclic Module Record, return _result_.
1. If _module_.[[Status]] is either ~evaluating~ or ~evaluated~, return _result_.
1. If _module_.[[HasTLA]] is *true*, then
1. Append _module_ to _result_.
1. Return _result_.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_, _seen_).
1. For each Module Record _m_ of _additionalModules_, do
1. If _result_ does not contain _m_, append _m_ to _result_.
1. Return _result_.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import "./dep-1_FIXTURE.js";
import defer * as ns2 from "./dep-2_FIXTURE.js";
import "./dep-3_FIXTURE.js";
import defer * as ns4 from "./dep-4_FIXTURE.js";
import "./dep-5_FIXTURE.js";
assert.compareArray(globalThis.evaluations, [
"1",
"2.1.1 start",
"2.2.1",
"2.2 start",
"3",
"5",
"2.1.1 end",
"2.2 end",
"4.1 start",
"4.1 end",
"5"
]);
globalThis.evaluations = [];
ns2.x;
assert.compareArray(globalThis.evaluations, ["2.1", "2"]);
globalThis.evaluations = [];
ns4.x;
assert.compareArray(globalThis.evaluations, ["4"]);
$DONE();

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations = [];

View File

@ -0,0 +1,55 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-innermoduleevaluation
description: >
`import defer` causes eager evaluation of dependencies with top-level await
info: |
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
GatherAsynchronousTransitiveDependencies ( _module_, [ _seen_ ] )
1. If _seen_ is not specified, let _seen_ be a new empty List.
1. Let _result_ be a new empty List.
1. If _seen_ contains _module_, return _result_.
1. Append _module_ to _seen_.
1. If _module_ is not a Cyclic Module Record, return _result_.
1. If _module_.[[Status]] is either ~evaluating~ or ~evaluated~, return _result_.
1. If _module_.[[HasTLA]] is *true*, then
1. Append _module_ to _result_.
1. Return _result_.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_, _seen_).
1. For each Module Record _m_ of _additionalModules_, do
1. If _result_ does not contain _m_, append _m_ to _result_.
1. Return _result_.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import defer * as ns from "./tla_FIXTURE.js";
assert.compareArray(globalThis.evaluations, ["tla start", "tla end"]);
ns.x;
assert.compareArray(globalThis.evaluations, ["tla start", "tla end"]);
$DONE();

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations = [];

View File

@ -0,0 +1,8 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("tla start");
await Promise.resolve(0);
globalThis.evaluations.push("tla end");

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./tla_FIXTURE.js";
globalThis.evaluations.push("imports-tla");

View File

@ -0,0 +1,55 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-innermoduleevaluation
description: >
`import defer` causes eager evaluation of transitive dependencies with top-level await
info: |
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
GatherAsynchronousTransitiveDependencies ( _module_, [ _seen_ ] )
1. If _seen_ is not specified, let _seen_ be a new empty List.
1. Let _result_ be a new empty List.
1. If _seen_ contains _module_, return _result_.
1. Append _module_ to _seen_.
1. If _module_ is not a Cyclic Module Record, return _result_.
1. If _module_.[[Status]] is either ~evaluating~ or ~evaluated~, return _result_.
1. If _module_.[[HasTLA]] is *true*, then
1. Append _module_ to _result_.
1. Return _result_.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_, _seen_).
1. For each Module Record _m_ of _additionalModules_, do
1. If _result_ does not contain _m_, append _m_ to _result_.
1. Return _result_.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import defer * as ns from "./imports-tla_FIXTURE.js";
assert.compareArray(globalThis.evaluations, ["tla start", "tla end"]);
ns.x;
assert.compareArray(globalThis.evaluations, ["tla start", "tla end", "imports-tla"]);
$DONE();

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations = [];

View File

@ -0,0 +1,8 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("tla start");
await Promise.resolve(0);
globalThis.evaluations.push("tla end");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations.push("dep");

View File

@ -0,0 +1,6 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./tla-with-dep_FIXTURE.js";
globalThis.evaluations.push("imports-tla-with-dep");

View File

@ -0,0 +1,61 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-innermoduleevaluation
description: >
`import defer` causes eager evaluation of synchronous dependencies of async dependencies
info: |
16.2.1.5.3.1 InnerModuleEvaluation ( _module_, _stack_, _index_ )
1. ...
1. Let _evaluationList_ be a new empty List.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. If _required_.[[Phase]] is ~defer~, then
i. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_).
ii. For each Module Record _additionalModule_ of _additionalModules_, do
1. If _evaluationList_ does not contain _additionalModule_, then
a. Append _additionalModule_ to _evaluationList_.
1. Else if _evaluationList_ does not contain _requiredModule_, then
i. Append _requiredModule_ to _evaluationList_.
1. ...
1. For each Module Record _requiredModule_ of _evaluationList_, do
1. Set _index_ to ? InnerModuleEvaluation(_requiredModule_, _stack_, _index_).
1. ...
GatherAsynchronousTransitiveDependencies ( _module_, [ _seen_ ] )
1. If _seen_ is not specified, let _seen_ be a new empty List.
1. Let _result_ be a new empty List.
1. If _seen_ contains _module_, return _result_.
1. Append _module_ to _seen_.
1. If _module_ is not a Cyclic Module Record, return _result_.
1. If _module_.[[Status]] is either ~evaluating~ or ~evaluated~, return _result_.
1. If _module_.[[HasTLA]] is *true*, then
1. Append _module_ to _result_.
1. Return _result_.
1. For each ModuleRequest Record _required_ of _module_.[[RequestedModules]], do
1. Let _requiredModule_ be GetImportedModule(_module_, _required_.[[Specifier]]).
1. Let _additionalModules_ be GatherAsynchronousTransitiveDependencies(_requiredModule_, _seen_).
1. For each Module Record _m_ of _additionalModules_, do
1. If _result_ does not contain _m_, append _m_ to _result_.
1. Return _result_.
flags: [module, async]
features: [import-defer, top-level-await]
includes: [compareArray.js]
---*/
import "./setup_FIXTURE.js";
import defer * as ns from "./imports-tla-with-dep_FIXTURE.js";
assert.compareArray(
globalThis.evaluations,
["dep", "tla-with-dep start", "tla-with-dep end"]
);
ns.x;
assert.compareArray(
globalThis.evaluations,
["dep", "tla-with-dep start", "tla-with-dep end", "imports-tla-with-dep"]
);
$DONE();

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
globalThis.evaluations = [];

View File

@ -0,0 +1,10 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
import "./dep_FIXTURE.js";
globalThis.evaluations.push("tla-with-dep start");
await Promise.resolve(0);
globalThis.evaluations.push("tla-with-dep end");

View File

@ -0,0 +1,4 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
export default 1;

View File

@ -0,0 +1,21 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` can be used with namespace imports
info: |
ImportDeclaration :
`import` ImportClause FromClause WithClause? `;`
`import` `defer` NameSpaceImport FromClause WithClause? `;`
`import` ModuleSpecifier WithClause? `;`
NameSpaceImport :
`*` `as` ImportedBinding
flags: [module]
features: [import-defer]
---*/
import defer * as ns from "./dep_FIXTURE.js" with { };

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` cannot be used if there are both a default and namespace bindings
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
NameSpaceImport
NamedImports
ImportedDefaultBinding `,` NameSpaceImport
ImportedDefaultBinding `,` NamedImports
NameSpaceImport :
`*` `as` ImportedBinding
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer x, * as ns from "./dep_FIXTURE.js";

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` must be followed by `*`
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
NameSpaceImport
NamedImports
ImportedDefaultBinding `,` NameSpaceImport
ImportedDefaultBinding `,` NamedImports
NameSpaceImport :
`*` `as` ImportedBinding
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer as ns from "./dep_FIXTURE.js";

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` cannot be used if there are both a default and namespace bindings
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
NameSpaceImport
NamedImports
ImportedDefaultBinding `,` NameSpaceImport
ImportedDefaultBinding `,` NamedImports
NameSpaceImport :
`*` `as` ImportedBinding
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
import x, defer * as ns from "./dep_FIXTURE.js";

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` cannot be used with default imports
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
NameSpaceImport
NamedImports
ImportedDefaultBinding `,` NameSpaceImport
ImportedDefaultBinding `,` NamedImports
NameSpaceImport :
`*` `as` ImportedBinding
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer x from "./dep_FIXTURE.js";

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` cannot be used with named imports
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
NameSpaceImport
NamedImports
ImportedDefaultBinding `,` NameSpaceImport
ImportedDefaultBinding `,` NamedImports
NameSpaceImport :
`*` `as` ImportedBinding
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
import defer { default as x } from "./dep_FIXTURE.js";

View File

@ -0,0 +1,32 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-exports
description: >
`export defer` is not valid
info: |
ExportDeclaration :
`export` ExportFromClause FromClause `;`
`export` NamedExports `;`
`export` VariableStatement
`export` Declaration
`export` `default` HoistableDeclaration
`export` `default` ClassDeclaration
`export` `default` [lookahead { function, async [no LineTerminator here] function, class }] AssignmentExpression `;`
ExportFromClause :
`*`
`*` `as` ModuleExportName
NamedExports
features: [import-defer]
negative:
phase: parse
type: SyntaxError
---*/
$DONOTEVALUATE();
export defer * as ns from "./dep_FIXTURE.js";

View File

@ -0,0 +1,30 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`defer` is a valid name for default imports
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
ImportClause :
ImportedDefaultBinding
...
ImportedDefaultBinding :
ImportedBinding
ImportedBinding :
BindingIdentifier[~Yield, +Await]
flags: [module]
features: [import-defer]
---*/
import defer from "./dep_FIXTURE.js";
asserts.sameValue(defer, 1, "`defer` is the default export binding");

View File

@ -0,0 +1,21 @@
// Copyright (C) 2024 Igalia, S.L. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: sec-imports
description: >
`import defer` can be used with namespace imports
info: |
ImportDeclaration :
`import` ImportClause FromClause `;`
`import` `defer` NameSpaceImport FromClause `;`
`import` ModuleSpecifier `;`
NameSpaceImport :
`*` `as` ImportedBinding
flags: [module]
features: [import-defer]
---*/
import defer * as ns from "./dep_FIXTURE.js";