Skip to content

Commit ee16a8b

Browse files
committed
fix(64627): reject deferred imports without namespace bindings
1 parent 50d70a3 commit ee16a8b

16 files changed

Lines changed: 226 additions & 20 deletions

‎tsc/internal/checker/grammarchecks.go‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2110,7 +2110,10 @@ func (c *Checker) checkGrammarImportClause(node *ast.ImportClause) bool {
21102110
if node.Name() != nil {
21112111
return c.grammarErrorOnNode(&node.Node, diagnostics.Default_imports_are_not_allowed_in_a_deferred_import)
21122112
}
2113-
if node.NamedBindings != nil && node.NamedBindings.Kind == ast.KindNamedImports {
2113+
if node.NamedBindings == nil {
2114+
return c.grammarErrorOnNode(&node.Node, diagnostics.A_deferred_import_must_specify_a_namespace_binding)
2115+
}
2116+
if node.NamedBindings.Kind == ast.KindNamedImports {
21142117
return c.grammarErrorOnNode(&node.Node, diagnostics.Named_imports_are_not_allowed_in_a_deferred_import)
21152118
}
21162119
if c.moduleKind.SupportsDeferredImports() {

‎tsc/internal/diagnostics/diagnosticMessages.generated.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,7 @@
19491949
"Source_phase_imports_are_only_supported_when_the_module_option_is_set_to_esnext_nodenext_or_preserve_18113": "Source phase imports are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'.",
19501950
"Optional_chaining_cannot_be_used_with_import_source_18114": "Optional chaining cannot be used with 'import.source'.",
19511951
"Source_phase_imports_are_not_allowed_on_statements_that_compile_to_CommonJS_require_calls_18115": "Source phase imports are not allowed on statements that compile to CommonJS 'require' calls.",
1952+
"A_deferred_import_must_specify_a_namespace_binding_18116": "A deferred import must specify a namespace binding.",
19521953
"nodenext_if_module_is_nodenext_node16_if_module_is_node16_or_node18_otherwise_bundler_69010": "`nodenext` if `module` is `nodenext`; `node16` if `module` is `node16` or `node18`; otherwise, `bundler`.",
19531954
"File_is_a_CommonJS_module_it_may_be_converted_to_an_ES_module_80001": "File is a CommonJS module; it may be converted to an ES module.",
19541955
"This_constructor_function_may_be_converted_to_a_class_declaration_80002": "This constructor function may be converted to a class declaration.",

‎tsc/internal/diagnostics/diagnosticMessages.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8915,5 +8915,9 @@
89158915
"Source phase imports are not allowed on statements that compile to CommonJS 'require' calls.": {
89168916
"category": "Error",
89178917
"code": 18115
8918+
},
8919+
"A deferred import must specify a namespace binding.": {
8920+
"category": "Error",
8921+
"code": 18116
89188922
}
89198923
}

‎tsc/internal/diagnostics/diagnostics_generated.go‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tsc/internal/parser/parser.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2409,7 +2409,7 @@ func (p *Parser) tryParseImportClause(identifier *ast.Node, pos int, phaseModifi
24092409
p.parseExpected(ast.KindFromKeyword)
24102410
return importClause
24112411
}
2412-
if phaseModifier == ast.KindSourceKeyword {
2412+
if phaseModifier == ast.KindDeferKeyword || phaseModifier == ast.KindSourceKeyword {
24132413
return p.finishNode(p.factory.NewImportClause(phaseModifier, nil /*name*/, nil /*namedBindings*/), pos)
24142414
}
24152415
return nil

‎tsc/internal/transformers/moduletransforms/externalmoduleinfo.go‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,5 @@ func getImportNeedsImportStarHelper(node *ast.ImportDeclaration) bool {
385385
func getImportNeedsImportDefaultHelper(node *ast.ImportDeclaration) bool {
386386
// Import default is needed if there's a default import or a default ref and no other refs (meaning an import star helper wasn't requested)
387387
return !getImportNeedsImportStarHelper(node) && (ast.IsDefaultImport(node.AsNode()) || (node.ImportClause != nil &&
388-
ast.IsNamedImports(node.ImportClause.AsImportClause().NamedBindings) &&
389388
containsDefaultReference(node.ImportClause.AsImportClause().NamedBindings)))
390389
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
b.ts(1,8): error TS18058: Default imports are not allowed in a deferred import.
2+
b.ts(5,8): error TS18116: A deferred import must specify a namespace binding.
3+
b.ts(6,8): error TS18116: A deferred import must specify a namespace binding.
4+
b.ts(6,23): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'node20', 'nodenext', or 'preserve'.
5+
c.js(1,8): error TS18116: A deferred import must specify a namespace binding.
6+
c.js(2,8): error TS18116: A deferred import must specify a namespace binding.
7+
c.js(2,23): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'node20', 'nodenext', or 'preserve'.
8+
9+
10+
==== a.ts (0 errors) ====
11+
export default function foo() {
12+
console.log("foo from a");
13+
}
14+
15+
==== b.ts (4 errors) ====
16+
import defer foo from "./a";
17+
~~~~~~~~~
18+
!!! error TS18058: Default imports are not allowed in a deferred import.
19+
20+
foo();
21+
22+
import defer "./a.js";
23+
~~~~~
24+
!!! error TS18116: A deferred import must specify a namespace binding.
25+
import defer "./a.js" with { type: "json" };
26+
~~~~~
27+
!!! error TS18116: A deferred import must specify a namespace binding.
28+
~~~~~~~~~~~~~~~~~~~~~
29+
!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'node20', 'nodenext', or 'preserve'.
30+
31+
==== c.js (3 errors) ====
32+
import defer "./a.js";
33+
~~~~~
34+
!!! error TS18116: A deferred import must specify a namespace binding.
35+
import defer "./a.js" with { type: "json" };
36+
~~~~~
37+
!!! error TS18116: A deferred import must specify a namespace binding.
38+
~~~~~~~~~~~~~~~~~~~~~
39+
!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'node18', 'node20', 'nodenext', or 'preserve'.
40+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//// [tests/cases/conformance/importDefer/importDeferInvalidDefault.ts] ////
2+
3+
//// [a.ts]
4+
export default function foo() {
5+
console.log("foo from a");
6+
}
7+
8+
//// [b.ts]
9+
import defer foo from "./a";
10+
11+
foo();
12+
13+
import defer "./a.js";
14+
import defer "./a.js" with { type: "json" };
15+
16+
//// [c.js]
17+
import defer "./a.js";
18+
import defer "./a.js" with { type: "json" };
19+
20+
21+
//// [a.js]
22+
"use strict";
23+
Object.defineProperty(exports, "__esModule", { value: true });
24+
exports.default = foo;
25+
function foo() {
26+
console.log("foo from a");
27+
}
28+
//// [b.js]
29+
"use strict";
30+
var __importDefault = (this && this.__importDefault) || function (mod) {
31+
return (mod && mod.__esModule) ? mod : { "default": mod };
32+
};
33+
Object.defineProperty(exports, "__esModule", { value: true });
34+
const a_1 = __importDefault(require("./a"));
35+
(0, a_1.default)();
36+
//// [c.js]
37+
"use strict";
38+
Object.defineProperty(exports, "__esModule", { value: true });
39+
const a_js_1 = require("./a.js");
40+
const a_js_2 = require("./a.js");

tsc/testdata/baselines/reference/conformance/importDeferInvalidDefault.symbols renamed to tsc/testdata/baselines/reference/conformance/importDeferInvalidDefault(module=commonjs).symbols

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,11 @@ import defer foo from "./a";
1717
foo();
1818
>foo : Symbol(foo, Decl(b.ts, 0, 6))
1919

20+
import defer "./a.js";
21+
import defer "./a.js" with { type: "json" };
22+
23+
=== c.js ===
24+
25+
import defer "./a.js";
26+
import defer "./a.js" with { type: "json" };
27+

tsc/testdata/baselines/reference/conformance/importDeferInvalidDefault.types renamed to tsc/testdata/baselines/reference/conformance/importDeferInvalidDefault(module=commonjs).types

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,12 @@ foo();
2020
>foo() : void
2121
>foo : () => void
2222

23+
import defer "./a.js";
24+
import defer "./a.js" with { type: "json" };
25+
>type : any
26+
27+
=== c.js ===
28+
import defer "./a.js";
29+
import defer "./a.js" with { type: "json" };
30+
>type : any
31+

0 commit comments

Comments
 (0)