Skip to content

Commit cfe1842

Browse files
authored
Add verbatimModuleSyntax, deprecate importsNotUsedAsValues and preserveValueImports (#52203)
1 parent ebbc56d commit cfe1842

File tree

108 files changed

+2882
-377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+2882
-377
lines changed

src/compiler/checker.ts

Lines changed: 140 additions & 59 deletions
Large diffs are not rendered by default.

src/compiler/commandLineParser.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,13 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [
789789
transpileOptionValue: true,
790790
defaultValueDescription: false,
791791
},
792+
{
793+
name: "verbatimModuleSyntax",
794+
type: "boolean",
795+
category: Diagnostics.Interop_Constraints,
796+
description: Diagnostics.Do_not_transform_or_elide_any_imports_or_exports_not_marked_as_type_only_ensuring_they_are_written_in_the_output_file_s_format_based_on_the_module_setting,
797+
defaultValueDescription: false,
798+
},
792799

793800
// Strict Type Checks
794801
{

src/compiler/diagnosticMessages.json

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@
635635
"category": "Error",
636636
"code": 1203
637637
},
638-
"Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.": {
638+
"Re-exporting a type when '{0}' is enabled requires using 'export type'.": {
639639
"category": "Error",
640640
"code": 1205
641641
},
@@ -647,10 +647,6 @@
647647
"category": "Error",
648648
"code": 1207
649649
},
650-
"'{0}' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.": {
651-
"category": "Error",
652-
"code": 1208
653-
},
654650
"Invalid optional chain from new expression. Did you mean to call '{0}()'?": {
655651
"category": "Error",
656652
"code": 1209
@@ -871,7 +867,7 @@
871867
"category": "Error",
872868
"code": 1268
873869
},
874-
"Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided.": {
870+
"Cannot use 'export import' on a type or type-only namespace when '{0}' is enabled.": {
875871
"category": "Error",
876872
"code": 1269
877873
},
@@ -915,6 +911,42 @@
915911
"category": "Error",
916912
"code": 1279
917913
},
914+
"Namespaces are not allowed in global script files when '{0}' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement.": {
915+
"category": "Error",
916+
"code": 1280
917+
},
918+
"Cannot access '{0}' from another file without qualification when '{1}' is enabled. Use '{2}' instead.": {
919+
"category": "Error",
920+
"code": 1281
921+
},
922+
"An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": {
923+
"category": "Error",
924+
"code": 1282
925+
},
926+
"An 'export =' declaration must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": {
927+
"category": "Error",
928+
"code": 1283
929+
},
930+
"An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": {
931+
"category": "Error",
932+
"code": 1284
933+
},
934+
"An 'export default' must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": {
935+
"category": "Error",
936+
"code": 1285
937+
},
938+
"ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.": {
939+
"category": "Error",
940+
"code": 1286
941+
},
942+
"A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.": {
943+
"category": "Error",
944+
"code": 1287
945+
},
946+
"An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled.": {
947+
"category": "Error",
948+
"code": 1288
949+
},
918950

919951
"'with' statements are not allowed in an async function block.": {
920952
"category": "Error",
@@ -1444,7 +1476,7 @@
14441476
"category": "Error",
14451477
"code": 1446
14461478
},
1447-
"'{0}' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled.": {
1479+
"'{0}' resolves to a type-only declaration and must be re-exported using a type-only re-export when '{1}' is enabled.": {
14481480
"category": "Error",
14491481
"code": 1448
14501482
},
@@ -1557,6 +1589,14 @@
15571589
"category": "Message",
15581590
"code": 1483
15591591
},
1592+
"'{0}' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.": {
1593+
"category": "Error",
1594+
"code": 1484
1595+
},
1596+
"'{0}' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.": {
1597+
"category": "Error",
1598+
"code": 1485
1599+
},
15601600

15611601
"The types of '{0}' are incompatible between these types.": {
15621602
"category": "Error",
@@ -3223,7 +3263,7 @@
32233263
"category": "Error",
32243264
"code": 2747
32253265
},
3226-
"Cannot access ambient const enums when the '--isolatedModules' flag is provided.": {
3266+
"Cannot access ambient const enums when '{0}' is enabled.": {
32273267
"category": "Error",
32283268
"code": 2748
32293269
},
@@ -4217,7 +4257,7 @@
42174257
"category": "Error",
42184258
"code": 5090
42194259
},
4220-
"Option 'preserveConstEnums' cannot be disabled when 'isolatedModules' is enabled.": {
4260+
"Option 'preserveConstEnums' cannot be disabled when '{0}' is enabled.": {
42214261
"category": "Error",
42224262
"code": 5091
42234263
},
@@ -4269,6 +4309,18 @@
42694309
"category": "Error",
42704310
"code": 5103
42714311
},
4312+
"Option '{0}' is redundant and cannot be specified with option '{1}'.": {
4313+
"category": "Error",
4314+
"code": 5104
4315+
},
4316+
"Option 'verbatimModuleSyntax' cannot be used when 'module' is set to 'UMD', 'AMD', or 'System'.": {
4317+
"category": "Error",
4318+
"code": 5105
4319+
},
4320+
"Use '{0}' instead.": {
4321+
"category": "Message",
4322+
"code": 5106
4323+
},
42724324

42734325
"Generates a sourcemap for each corresponding '.d.ts' file.": {
42744326
"category": "Message",
@@ -6003,6 +6055,10 @@
60036055
"category": "Message",
60046056
"code": 6803
60056057
},
6058+
"Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting.": {
6059+
"category": "Message",
6060+
"code": 6804
6061+
},
60066062

60076063
"one of:": {
60086064
"category": "Message",

src/compiler/program.ts

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
createCompilerDiagnostic,
3636
createCompilerDiagnosticFromMessageChain,
3737
createDiagnosticCollection,
38+
createDiagnosticForNodeFromMessageChain,
3839
createDiagnosticForNodeInSourceFile,
3940
createDiagnosticForRange,
4041
createFileDiagnostic,
@@ -4117,21 +4118,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
41174118
const languageVersion = getEmitScriptTarget(options);
41184119

41194120
const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile);
4120-
if (options.isolatedModules) {
4121-
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
4121+
if (options.isolatedModules || options.verbatimModuleSyntax) {
4122+
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015 && options.isolatedModules) {
41224123
createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
41234124
}
41244125

41254126
if (options.preserveConstEnums === false) {
4126-
createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules");
4127-
}
4128-
4129-
for (const file of files) {
4130-
if (!isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile && file.scriptKind !== ScriptKind.JSON) {
4131-
const span = getErrorSpanForNode(file, file);
4132-
programDiagnostics.add(createFileDiagnostic(file, span.start, span.length,
4133-
Diagnostics._0_cannot_be_compiled_under_isolatedModules_because_it_is_considered_a_global_script_file_Add_an_import_export_or_an_empty_export_statement_to_make_it_a_module, getBaseFileName(file.fileName)));
4134-
}
4127+
createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_0_is_enabled, options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", "preserveConstEnums");
41354128
}
41364129
}
41374130
else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) {
@@ -4240,7 +4233,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
42404233
}
42414234

42424235
if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) {
4243-
createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later);
4236+
createDiagnosticForOptionName(Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later, "preserveValueImports");
4237+
}
4238+
4239+
if (options.verbatimModuleSyntax) {
4240+
const moduleKind = getEmitModuleKind(options);
4241+
if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.UMD || moduleKind === ModuleKind.System) {
4242+
createDiagnosticForOptionName(Diagnostics.Option_verbatimModuleSyntax_cannot_be_used_when_module_is_set_to_UMD_AMD_or_System, "verbatimModuleSyntax");
4243+
}
4244+
if (options.isolatedModules) {
4245+
createRedundantOptionDiagnostic("isolatedModules", "verbatimModuleSyntax");
4246+
}
4247+
if (options.preserveValueImports) {
4248+
createRedundantOptionDiagnostic("preserveValueImports", "verbatimModuleSyntax");
4249+
}
4250+
if (options.importsNotUsedAsValues) {
4251+
createRedundantOptionDiagnostic("importsNotUsedAsValues", "verbatimModuleSyntax");
4252+
}
42444253
}
42454254

42464255
if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly)) {
@@ -4333,15 +4342,35 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
43334342
if (options.out) {
43344343
createDeprecatedDiagnosticForOption(version, "out");
43354344
}
4345+
if (options.importsNotUsedAsValues) {
4346+
createDeprecatedDiagnosticForOption(version, "importsNotUsedAsValues", /*value*/ undefined, "verbatimModuleSyntax");
4347+
}
4348+
if (options.preserveValueImports) {
4349+
createDeprecatedDiagnosticForOption(version, "preserveValueImports", /*value*/ undefined, "verbatimModuleSyntax");
4350+
}
43364351
}
43374352

4338-
function createDeprecatedDiagnosticForOption(version: string, name: string, value?: string) {
4353+
function createDeprecatedDiagnosticForOption(version: string, name: string, value?: string, useInstead?: string) {
43394354
if (version === DeprecationVersion.v6_0) {
4340-
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name);
4355+
if (useInstead) {
4356+
const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead);
4357+
const chain = chainDiagnosticMessages(details, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name);
4358+
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, chain);
4359+
}
4360+
else {
4361+
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name);
4362+
}
43414363
}
43424364
else {
4343-
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined,
4344-
Diagnostics.Flag_0_is_deprecated_and_will_stop_functioning_in_TypeScript_1_Specify_ignoreDeprecations_Colon_2_to_silence_this_error, value || name, DeprecationVersion.v5_5, DeprecationVersion.v5_0);
4365+
if (useInstead) {
4366+
const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead);
4367+
const chain = chainDiagnosticMessages(details, Diagnostics.Flag_0_is_deprecated_and_will_stop_functioning_in_TypeScript_1_Specify_ignoreDeprecations_Colon_2_to_silence_this_error, value || name, DeprecationVersion.v5_5, DeprecationVersion.v5_0);
4368+
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, chain);
4369+
}
4370+
else {
4371+
createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined,
4372+
Diagnostics.Flag_0_is_deprecated_and_will_stop_functioning_in_TypeScript_1_Specify_ignoreDeprecations_Colon_2_to_silence_this_error, value || name, DeprecationVersion.v5_5, DeprecationVersion.v5_0);
4373+
}
43454374
}
43464375
}
43474376

@@ -4590,13 +4619,21 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
45904619
}
45914620
}
45924621

4593-
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) {
4622+
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessageChain): void;
4623+
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): void;
4624+
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): void {
45944625
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
45954626
const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax ||
45964627
!createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2);
45974628

45984629
if (needCompilerDiagnostic) {
4599-
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
4630+
// eslint-disable-next-line local/no-in-operator
4631+
if ("messageText" in message) {
4632+
programDiagnostics.add(createCompilerDiagnosticFromMessageChain(message));
4633+
}
4634+
else {
4635+
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2));
4636+
}
46004637
}
46014638
}
46024639

@@ -4616,14 +4653,43 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
46164653
return _compilerOptionsObjectLiteralSyntax || undefined;
46174654
}
46184655

4619-
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean {
4656+
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, messageChain: DiagnosticMessageChain): boolean;
4657+
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean;
4658+
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean;
4659+
function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean {
46204660
const props = getPropertyAssignment(objectLiteral, key1, key2);
46214661
for (const prop of props) {
4622-
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2));
4662+
// eslint-disable-next-line local/no-in-operator
4663+
if ("messageText" in message) {
4664+
programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message));
4665+
}
4666+
else {
4667+
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2));
4668+
}
46234669
}
46244670
return !!props.length;
46254671
}
46264672

4673+
/**
4674+
* Only creates a diagnostic on the option key specified by `errorOnOption`.
4675+
* If both options are specified in the program in separate config files via `extends`,
4676+
* a diagnostic is only created if `errorOnOption` is specified in the leaf config file.
4677+
* Useful if `redundantWithOption` represents a superset of the functionality of `errorOnOption`:
4678+
* if a user inherits `errorOnOption` from a base config file, it's still valid and useful to
4679+
* override it in the leaf config file.
4680+
*/
4681+
function createRedundantOptionDiagnostic(errorOnOption: string, redundantWithOption: string) {
4682+
const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax();
4683+
if (compilerOptionsObjectLiteralSyntax) {
4684+
// This is a no-op if `errorOnOption` isn't present in the leaf config file.
4685+
createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, /*onKey*/ true, errorOnOption, /*key2*/ undefined, Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption);
4686+
}
4687+
else {
4688+
// There was no config file, so both options were specified on the command line.
4689+
createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption);
4690+
}
4691+
}
4692+
46274693
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
46284694
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
46294695
programDiagnostics.add(diag);

0 commit comments

Comments
 (0)