Skip to content

Commit 736e677

Browse files
committed
[export-defer] Add export defer namespace-object evaluation-triggers cases
Test the observable deferred evaluation semantics of `export defer` namespace objects. The proposal only inserts EvaluateModuleSync into [[Get]], so only operations that route through [[Get]] on the namespace object trigger deferred source evaluation. Tests use three template families that reflect this classification: trigger-on-exported/ (4 variants: string-exported, string-not-exported, then-exported, then-not-exported) For operations that route through [[Get]] and trigger evaluation when the key is a deferred-reexported name. The string-not-exported and then-not-exported variants verify that non-exported keys do NOT trigger (the [[Get]] returns undefined before reaching GetOptionalIndirectExportsModuleRequests). no-trigger-on-exported/ (4 variants: string-exported, string-not-exported, then-exported, then-not-exported) For key-sensitive operations that never route through [[Get]]. no-trigger/ (1 variant: no key) For operations that take no property key or where the key is irrelevanr, ns evaluation is never triggered.
1 parent 458e815 commit 736e677

29 files changed

Lines changed: 678 additions & 0 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-defineownproperty-p-desc
6+
desc: _ [[DefineOwnProperty]]
7+
info: |
8+
[[DefineOwnProperty]] ( _P_, _Desc_ )
9+
1. If _P_ is a Symbol, return OrdinaryDefineOwnProperty(_O_, _P_, _Desc_).
10+
1. Let _current_ be ? _O_.[[GetOwnProperty]](_P_).
11+
1. If _current_ is *undefined*, return *false*.
12+
1. ...
13+
14+
template: trigger-on-exported
15+
---*/
16+
17+
//- body
18+
try {
19+
Object.defineProperty(ns, key, { value: "hi" });
20+
} catch (_) {}

src/export-defer/delete.case

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-delete-p
6+
desc: _ [[Delete]]
7+
info: |
8+
[[Delete]] ( _P_ )
9+
1. If _P_ is a Symbol, return OrdinaryDelete(_O_, _P_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ contains _P_, return *false*.
12+
1. Return *true*.
13+
14+
template: no-trigger-on-exported
15+
---*/
16+
17+
//- body
18+
try {
19+
delete ns[key];
20+
} catch (_) {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-get-p-receiver
6+
desc: _ [[Get]] when namespace object is in the prototype chain
7+
info: |
8+
[[Get]] ( _P_, _Receiver_ )
9+
1. If _P_ is a Symbol, return OrdinaryGet(_O_, _P_, _Receiver_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ does not contain _P_, return *undefined*.
12+
1. ...
13+
14+
template: trigger-on-exported
15+
---*/
16+
17+
//- body
18+
const obj = Object.create(ns);
19+
obj[key];

src/export-defer/get.case

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-get-p-receiver
6+
desc: _ [[Get]]
7+
info: |
8+
[[Get]] ( _P_, _Receiver_ )
9+
1. If _P_ is a Symbol, return OrdinaryGet(_O_, _P_, _Receiver_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ does not contain _P_, return *undefined*.
12+
1. ...
13+
14+
template: trigger-on-exported
15+
---*/
16+
17+
//- body
18+
ns[key];
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-getownproperty-p
6+
desc: _ [[GetOwnProperty]]
7+
info: |
8+
[[GetOwnProperty]] ( _P_ )
9+
1. If _P_ is a Symbol, return OrdinaryGetOwnProperty(_O_, _P_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ does not contain _P_, return *undefined*.
12+
1. Let value be ? _O_.[[Get]](_P_, _O_).
13+
1. Return PropertyDescriptor { [[Value]]: _value_, [[Writable]]: *true*, [[Enumerable]]: *true*, [[Configurable]]: *false* }.
14+
15+
template: trigger-on-exported
16+
---*/
17+
18+
//- body
19+
Object.getOwnPropertyDescriptor(ns, key);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-hasproperty-p
6+
desc: _ [[HasProperty]] when namespace object is in the prototype chain
7+
info: |
8+
[[HasProperty]] ( _P_ )
9+
1. If _P_ is a Symbol, return OrdinaryHasProperty(_O_, _P_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ contains _P_, return *true*.
12+
1. Return *false*.
13+
14+
template: no-trigger-on-exported
15+
---*/
16+
17+
//- body
18+
const obj = Object.create(ns);
19+
key in obj;

src/export-defer/hasProperty.case

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-module-namespace-exotic-objects-hasproperty-p
6+
desc: _ [[HasProperty]]
7+
info: |
8+
[[HasProperty]] ( _P_ )
9+
1. If _P_ is a Symbol, return OrdinaryHasProperty(_O_, _P_).
10+
1. Let _exports_ be _O_.[[Exports]].
11+
1. If _exports_ contains _P_, return *true*.
12+
1. Return *false*.
13+
14+
template: no-trigger-on-exported
15+
---*/
16+
17+
//- body
18+
key in ns;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
path: language/export/export-defer/evaluation-triggers/ignore-exported-string-
6+
name: of a string that is a deferred-reexported name, does not trigger evaluation
7+
esid: sec-module-namespace-exotic-objects
8+
info: |
9+
EvaluateModuleSync is only inserted into [[Get]] by this proposal.
10+
Operations that do not route through [[Get]] do not reach it,
11+
even for a deferred-reexported name.
12+
13+
flags: [module]
14+
features: [export-defer]
15+
includes: [compareArray.js]
16+
---*/
17+
18+
import "./setup_FIXTURE.js";
19+
20+
import * as ns from "./barrel_FIXTURE.js";
21+
22+
assert.compareArray(globalThis.evaluations, ["barrel"],
23+
"barrel evaluated eagerly; deferred source not yet evaluated");
24+
25+
var key = "exported";
26+
27+
/*{ body }*/
28+
29+
assert.compareArray(globalThis.evaluations, ["barrel"],
30+
"operation does not route through [[Get]], so deferred source is not evaluated");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
path: language/export/export-defer/evaluation-triggers/ignore-not-exported-string-
6+
name: of a string that is not a deferred-reexported name, does not trigger evaluation
7+
esid: sec-module-namespace-exotic-objects
8+
info: |
9+
EvaluateModuleSync is only inserted into [[Get]] by this proposal.
10+
Operations that do not route through [[Get]] do not reach it,
11+
even for a deferred-reexported name.
12+
13+
flags: [module]
14+
features: [export-defer]
15+
includes: [compareArray.js]
16+
---*/
17+
18+
import "./setup_FIXTURE.js";
19+
20+
import * as ns from "./barrel_FIXTURE.js";
21+
22+
assert.compareArray(globalThis.evaluations, ["barrel"],
23+
"barrel evaluated eagerly; deferred source not yet evaluated");
24+
25+
var key = "notExported";
26+
27+
/*{ body }*/
28+
29+
assert.compareArray(globalThis.evaluations, ["barrel"],
30+
"operation does not route through [[Get]], so deferred source is not evaluated");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (C) 2026 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
path: language/export/export-defer/evaluation-triggers/ignore-exported-then-
6+
name: of "then" when it is a deferred-reexported name, does not trigger evaluation
7+
esid: sec-module-namespace-exotic-objects
8+
info: |
9+
EvaluateModuleSync is only inserted into [[Get]] by this proposal.
10+
Operations that do not route through [[Get]] do not reach it,
11+
even for a deferred-reexported name.
12+
13+
flags: [module]
14+
features: [export-defer]
15+
includes: [compareArray.js]
16+
---*/
17+
18+
import "./setup_FIXTURE.js";
19+
20+
import * as ns from "./barrel-then_FIXTURE.js";
21+
22+
assert.compareArray(globalThis.evaluations, ["barrel"],
23+
"barrel evaluated eagerly; deferred source not yet evaluated");
24+
25+
var key = "then";
26+
27+
/*{ body }*/
28+
29+
assert.compareArray(globalThis.evaluations, ["barrel"],
30+
"operation does not route through [[Get]], so deferred source is not evaluated");

0 commit comments

Comments
 (0)