Skip to content

Commit 9769291

Browse files
Add test for difference between export * as x from and import * as x; export { x }
1 parent bc19854 commit 9769291

12 files changed

+359
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
/*---
4+
description: A binding re-exported with `export { foo } from` and `import { foo } from; export { foo }` does not cause ambiguity.
5+
esid: sec-source-text-module-record-initialize-environment
6+
info: |
7+
[...]
8+
7. For each ImportEntry Record in of module.[[ImportEntries]], do
9+
a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
10+
b. If in.[[ImportName]] is namespace-object, then
11+
i. Let namespace be GetModuleNamespace(importedModule).
12+
ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
13+
iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
14+
c. Else,
15+
i. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
16+
ii. If resolution is either null or ambiguous, throw a SyntaxError exception.
17+
18+
Table 59 (Informative): Export Forms Mappings to ExportEntry Records
19+
20+
Export Statement Form [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
21+
export {x}; "x" null null "x"
22+
export {x} from "mod"; "x" "mod" "x" null
23+
24+
16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )
25+
[...]
26+
10. For each ExportEntry Record ee of exportEntries, do
27+
1. If ee.[[ModuleRequest]] is null, then
28+
i. If importedBoundNames does not contain ee.[[LocalName]], then
29+
1. Append ee to localExportEntries.
30+
ii. Else,
31+
1. Let ie be the element of importEntries whose [[LocalName]] is ee.[[LocalName]].
32+
2. If ie.[[ImportName]] is namespace-object, then
33+
a. NOTE: This is a re-export of an imported module namespace object.
34+
b. Append ee to localExportEntries.
35+
3. Else,
36+
a. NOTE: This is a re-export of a single name.
37+
b. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]],
38+
[[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]:
39+
ee.[[ExportName]] } to indirectExportEntries.
40+
2. Else if ee.[[ImportName]] is all-but-default, then
41+
[...]
42+
3. Else,
43+
a. Append ee to indirectExportEntries.
44+
45+
15.2.1.16.3 ResolveExport
46+
47+
[...]
48+
6. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
49+
a. If e.[[ExportName]] is exportName, then
50+
i. Assert: e.[[ModuleRequest]] is not null.
51+
ii. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
52+
iii. If e.[[ImportName]] is all, then
53+
1. Assert: module does not provide the direct binding for this export.
54+
2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
55+
[...]
56+
9. Let starResolution be null.
57+
10. For each ExportEntry Record e in module.[[StarExportEntries]], do
58+
a. Let importedModule be GetImportedModule(module,
59+
e.[[ModuleRequest]]).
60+
b. Let resolution be ? importedModule.ResolveExport(exportName,
61+
resolveSet, exportStarSet).
62+
c. If resolution is ~ambiguous~, return ~ambiguous~.
63+
d. If resolution is not null, then
64+
i. If starResolution is null, let starResolution be resolution.
65+
ii. Else,
66+
1. Assert: there is more than one * import that includes the
67+
requested name.
68+
2. If _resolution_.[[Module]] and _starResolution_.[[Module]] are
69+
not the same Module Record, return ~ambiguous~.
70+
3. If _resolution_.[[BindingName]] is not _starResolution_.[[BindingName]],
71+
return ~ambiguous~.
72+
flags: [module]
73+
---*/
74+
75+
export * from "./namespace-export-star-as-from-1_FIXTURE.js";
76+
export * from "./import-and-export-propagates-binding_import-and-export_FIXTURE.js";
77+
78+
import { foo } from './import-and-export-propagates-binding.js';
79+
80+
assert.sameValue(foo, 3);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
export const foo = 2;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
export { foo } from "./import-and-export-propagates-binding_FIXTURE.js";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
import { foo } from "./import-and-export-propagates-binding_FIXTURE.js";
5+
export { foo };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
/*---
4+
description: Statements `export * as foo` and `import * as foo; export { foo }` are different bindings
5+
esid: sec-source-text-module-record-initialize-environment
6+
info: |
7+
[...]
8+
7. For each ImportEntry Record in of module.[[ImportEntries]], do
9+
a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
10+
b. If in.[[ImportName]] is namespace-object, then
11+
i. Let namespace be GetModuleNamespace(importedModule).
12+
ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
13+
iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
14+
c. Else,
15+
i. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
16+
ii. If resolution is either null or ambiguous, throw a SyntaxError exception.
17+
18+
Table 59 (Informative): Export Forms Mappings to ExportEntry Records
19+
20+
Export Statement Form [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
21+
export {x}; "x" null null "x"
22+
export * as ns from "mod"; "ns" "mod" all null
23+
24+
16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )
25+
[...]
26+
10. For each ExportEntry Record ee of exportEntries, do
27+
1. If ee.[[ModuleRequest]] is null, then
28+
i. If importedBoundNames does not contain ee.[[LocalName]], then
29+
1. Append ee to localExportEntries.
30+
ii. Else,
31+
1. Let ie be the element of importEntries whose [[LocalName]] is ee.[[LocalName]].
32+
2. If ie.[[ImportName]] is namespace-object, then
33+
a. NOTE: This is a re-export of an imported module namespace object.
34+
b. Append ee to localExportEntries.
35+
3. Else,
36+
a. NOTE: This is a re-export of a single name.
37+
b. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]],
38+
[[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]:
39+
ee.[[ExportName]] } to indirectExportEntries.
40+
2. Else if ee.[[ImportName]] is all-but-default, then
41+
[...]
42+
3. Else,
43+
a. Append ee to indirectExportEntries.
44+
45+
15.2.1.16.3 ResolveExport
46+
47+
[...]
48+
6. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
49+
a. If e.[[ExportName]] is exportName, then
50+
i. Assert: e.[[ModuleRequest]] is not null.
51+
ii. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
52+
iii. If e.[[ImportName]] is all, then
53+
1. Assert: module does not provide the direct binding for this export.
54+
2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
55+
[...]
56+
9. Let starResolution be null.
57+
10. For each ExportEntry Record e in module.[[StarExportEntries]], do
58+
a. Let importedModule be GetImportedModule(module,
59+
e.[[ModuleRequest]]).
60+
b. Let resolution be ? importedModule.ResolveExport(exportName,
61+
resolveSet, exportStarSet).
62+
c. If resolution is ~ambiguous~, return ~ambiguous~.
63+
d. If resolution is not null, then
64+
i. If starResolution is null, let starResolution be resolution.
65+
ii. Else,
66+
1. Assert: there is more than one * import that includes the
67+
requested name.
68+
2. If _resolution_.[[Module]] and _starResolution_.[[Module]] are
69+
not the same Module Record, return ~ambiguous~.
70+
3. If _resolution_.[[BindingName]] is not _starResolution_.[[BindingName]],
71+
return ~ambiguous~.
72+
negative:
73+
phase: resolution
74+
type: SyntaxError
75+
flags: [module]
76+
---*/
77+
78+
$DONOTEVALUATE();
79+
80+
export * from "./namespace-export-star-as-from-1_FIXTURE.js";
81+
export * from "./namespace-import-star-as-and-export-1_FIXTURE.js";
82+
83+
import { foo } from './namespace-ambiguous-if-import-star-as-and-export.js';
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
/*---
4+
description: Two copies of `import * as foo; export { foo }` are different bindings
5+
esid: sec-source-text-module-record-initialize-environment
6+
info: |
7+
[...]
8+
7. For each ImportEntry Record in of module.[[ImportEntries]], do
9+
a. Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]).
10+
b. If in.[[ImportName]] is namespace-object, then
11+
i. Let namespace be GetModuleNamespace(importedModule).
12+
ii. Perform ! env.CreateImmutableBinding(in.[[LocalName]], true).
13+
iii. Perform ! env.InitializeBinding(in.[[LocalName]], namespace).
14+
c. Else,
15+
i. Let resolution be importedModule.ResolveExport(in.[[ImportName]]).
16+
ii. If resolution is either null or ambiguous, throw a SyntaxError exception.
17+
18+
Table 59 (Informative): Export Forms Mappings to ExportEntry Records
19+
20+
Export Statement Form [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
21+
export {x}; "x" null null "x"
22+
export * as ns from "mod"; "ns" "mod" all null
23+
24+
16.2.1.7.1 ParseModule ( sourceText, realm, hostDefined )
25+
[...]
26+
10. For each ExportEntry Record ee of exportEntries, do
27+
1. If ee.[[ModuleRequest]] is null, then
28+
i. If importedBoundNames does not contain ee.[[LocalName]], then
29+
1. Append ee to localExportEntries.
30+
ii. Else,
31+
1. Let ie be the element of importEntries whose [[LocalName]] is ee.[[LocalName]].
32+
2. If ie.[[ImportName]] is namespace-object, then
33+
a. NOTE: This is a re-export of an imported module namespace object.
34+
b. Append ee to localExportEntries.
35+
3. Else,
36+
a. NOTE: This is a re-export of a single name.
37+
b. Append the ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]],
38+
[[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]:
39+
ee.[[ExportName]] } to indirectExportEntries.
40+
2. Else if ee.[[ImportName]] is all-but-default, then
41+
[...]
42+
3. Else,
43+
a. Append ee to indirectExportEntries.
44+
45+
15.2.1.16.3 ResolveExport
46+
47+
[...]
48+
6. For each ExportEntry Record e of module.[[IndirectExportEntries]], do
49+
a. If e.[[ExportName]] is exportName, then
50+
i. Assert: e.[[ModuleRequest]] is not null.
51+
ii. Let importedModule be GetImportedModule(module, e.[[ModuleRequest]]).
52+
iii. If e.[[ImportName]] is all, then
53+
1. Assert: module does not provide the direct binding for this export.
54+
2. Return ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: namespace }.
55+
[...]
56+
9. Let starResolution be null.
57+
10. For each ExportEntry Record e in module.[[StarExportEntries]], do
58+
a. Let importedModule be GetImportedModule(module,
59+
e.[[ModuleRequest]]).
60+
b. Let resolution be ? importedModule.ResolveExport(exportName,
61+
resolveSet, exportStarSet).
62+
c. If resolution is ~ambiguous~, return ~ambiguous~.
63+
d. If resolution is not null, then
64+
i. If starResolution is null, let starResolution be resolution.
65+
ii. Else,
66+
1. Assert: there is more than one * import that includes the
67+
requested name.
68+
2. If _resolution_.[[Module]] and _starResolution_.[[Module]] are
69+
not the same Module Record, return ~ambiguous~.
70+
3. If _resolution_.[[BindingName]] is not _starResolution_.[[BindingName]],
71+
return ~ambiguous~.
72+
negative:
73+
phase: resolution
74+
type: SyntaxError
75+
flags: [module]
76+
---*/
77+
78+
$DONOTEVALUATE();
79+
80+
export * from "./namespace-import-star-as-and-export-1_FIXTURE.js";
81+
export * from "./namespace-import-star-as-and-export-2_FIXTURE.js";
82+
83+
import { foo } from './namespace-ambiguous-if-import-star-as-and-export.js';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
export * as foo from "./namespace-empty-module_FIXTURE.js";
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
export * as foo from "./namespace-empty-module_FIXTURE.js";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
import * as foo from "./namespace-empty-module_FIXTURE.js";
5+
export { foo };

0 commit comments

Comments
 (0)