From 5ebc60689e10b9c4acb8dd8c7df48ed68c5dae4d Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 7 Dec 2022 15:39:02 -0800 Subject: [PATCH 01/15] Add flag and update diagnostic messages --- src/compiler/commandLineParser.ts | 7 +++++ src/compiler/diagnosticMessages.json | 42 ++++++++++++++++++++++------ src/compiler/program.ts | 18 +++++++++++- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 10 +++++++ 5 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index b62fb3b638ff1..dc6448eb909cc 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -783,6 +783,13 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ transpileOptionValue: true, defaultValueDescription: false, }, + { + name: "verbatimModuleSyntax", + type: "boolean", + category: Diagnostics.Interop_Constraints, + 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, + defaultValueDescription: false, + }, // Strict Type Checks { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e146cce88c8cb..7e63080a32dea 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -635,7 +635,7 @@ "category": "Error", "code": 1203 }, - "Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'.": { + "Re-exporting a type when '{0}' is enabled requires using 'export type'.": { "category": "Error", "code": 1205 }, @@ -647,10 +647,6 @@ "category": "Error", "code": 1207 }, - "'{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.": { - "category": "Error", - "code": 1208 - }, "Invalid optional chain from new expression. Did you mean to call '{0}()'?": { "category": "Error", "code": 1209 @@ -875,7 +871,7 @@ "category": "Error", "code": 1268 }, - "Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided.": { + "Cannot use 'export import' on a type or type-only namespace when '{0}' is enabled.": { "category": "Error", "code": 1269 }, @@ -907,6 +903,14 @@ "category": "Error", "code": 1276 }, + "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.": { + "category": "Error", + "code": 1277 + }, + "Top-level enums 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.": { + "category": "Error", + "code": 1278 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", @@ -1436,7 +1440,7 @@ "category": "Error", "code": 1446 }, - "'{0}' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled.": { + "'{0}' resolves to a type-only declaration and must be re-exported using a type-only re-export when '{1}' is enabled.": { "category": "Error", "code": 1448 }, @@ -1549,6 +1553,14 @@ "category": "Message", "code": 1483 }, + "'{0}' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1484 + }, + "'{0}' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1485 + }, "The types of '{0}' are incompatible between these types.": { "category": "Error", @@ -3215,7 +3227,7 @@ "category": "Error", "code": 2747 }, - "Cannot access ambient const enums when the '--isolatedModules' flag is provided.": { + "Cannot access ambient const enums when '{0}' is enabled.": { "category": "Error", "code": 2748 }, @@ -4201,7 +4213,7 @@ "category": "Error", "code": 5090 }, - "Option 'preserveConstEnums' cannot be disabled when 'isolatedModules' is enabled.": { + "Option 'preserveConstEnums' cannot be disabled when '{0}' is enabled.": { "category": "Error", "code": 5091 }, @@ -4221,6 +4233,14 @@ "category": "Error", "code": 5095 }, + "Option '{0}' is redundant and cannot be specified with option '{1}'.": { + "category": "Error", + "code": 5096 + }, + "Option 'verbatimModuleSyntax' cannot be used when 'module' is set to 'UMD', 'AMD', or 'System'.": { + "category": "Error", + "code": 5097 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", @@ -5919,6 +5939,10 @@ "category": "Message", "code": 6803 }, + "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.": { + "category": "Message", + "code": 6804 + }, "one of:": { "category": "Message", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index ea600b28df784..942a45a78c987 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -4211,7 +4211,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if (options.preserveValueImports && getEmitModuleKind(options) < ModuleKind.ES2015) { - createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later); + createDiagnosticForOptionName(Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later, "preserveValueImports"); + } + + if (options.verbatimModuleSyntax) { + const moduleKind = getEmitModuleKind(options); + if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.UMD || moduleKind === ModuleKind.System) { + createDiagnosticForOptionName(Diagnostics.Option_verbatimModuleSyntax_cannot_be_used_when_module_is_set_to_UMD_AMD_or_System, "verbatimModuleSyntax"); + } + if (options.isolatedModules) { + createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "isolatedModules", "verbatimModuleSyntax"); + } + if (options.preserveValueImports) { + createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "preserveValueImports", "verbatimModuleSyntax"); + } + if (options.importsNotUsedAsValues) { + createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "importsNotUsedAsValues", "verbatimModuleSyntax"); + } } // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 47db014d8ae2b..108c54fa33235 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6797,6 +6797,7 @@ export interface CompilerOptions { types?: string[]; /** Paths used to compute primary types search locations */ typeRoots?: string[]; + verbatimModuleSyntax?: boolean; /** @internal */ version?: boolean; /** @internal */ watch?: boolean; esModuleInterop?: boolean; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b2cc2fb99f323..68aab9b889f73 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7573,6 +7573,16 @@ export function hasJsonModuleEmitEnabled(options: CompilerOptions) { } } +/** @internal */ +export function getIsolatedModules(options: CompilerOptions) { + return !!(options.isolatedModules || options.verbatimModuleSyntax); +} + +/** @internal */ +export function importNameElisionDisabled(options: CompilerOptions) { + return options.verbatimModuleSyntax || options.isolatedModules && options.preserveValueImports; +} + /** @internal */ export function unreachableCodeIsError(options: CompilerOptions): boolean { return options.allowUnreachableCode === false; From c1de572810c78b6af2b474fa4b7710650d2d3b62 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 8 Dec 2022 11:02:22 -0800 Subject: [PATCH 02/15] Finish updating error messages --- src/compiler/checker.ts | 42 ++++++++++++------- src/compiler/diagnosticMessages.json | 2 +- src/compiler/program.ts | 14 ++----- .../codefixes/convertToTypeOnlyExport.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../verbatimModuleSyntax/tsconfig.json | 5 +++ .../importHelpersInIsolatedModules.errors.txt | 37 ---------------- ...isolatedModulesAmbientConstEnum.errors.txt | 4 +- ...rtImportUninstantiatedNamespace.errors.txt | 4 +- ...isolatedModulesNoExternalModule.errors.txt | 7 ---- ...ModulesNoExternalModuleMultiple.errors.txt | 20 --------- .../reference/isolatedModulesOut.errors.txt | 7 +--- .../isolatedModulesPlainFile-AMD.errors.txt | 9 ---- ...olatedModulesPlainFile-CommonJS.errors.txt | 9 ---- .../isolatedModulesPlainFile-ES6.errors.txt | 9 ---- ...isolatedModulesPlainFile-System.errors.txt | 9 ---- .../isolatedModulesPlainFile-UMD.errors.txt | 9 ---- .../isolatedModulesReExportType.errors.txt | 12 +++--- ...ts_errors(isolatedmodules=true).errors.txt | 4 +- ...elf-if-'--isolatedModules'-is-specified.js | 14 +------ 32 files changed, 67 insertions(+), 165 deletions(-) create mode 100644 tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json delete mode 100644 tests/baselines/reference/importHelpersInIsolatedModules.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesNoExternalModule.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesNoExternalModuleMultiple.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesPlainFile-AMD.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesPlainFile-CommonJS.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesPlainFile-ES6.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesPlainFile-System.errors.txt delete mode 100644 tests/baselines/reference/isolatedModulesPlainFile-UMD.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 22452a4eb328b..ad69b5371905f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -268,6 +268,7 @@ import { getInitializerOfBinaryExpression, getInterfaceBaseTypeNodes, getInvokedExpression, + getIsolatedModules, getJSDocClassTag, getJSDocDeprecatedTag, getJSDocEnumTag, @@ -1406,6 +1407,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String); const requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String); + const isolatedModulesLikeFlagName = compilerOptions.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules"; /** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */ let apparentArgumentCount: number | undefined; @@ -3014,6 +3016,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.EnumDeclaration: if (result = lookup(getSymbolOfNode(location)?.exports || emptySymbols, name, meaning & SymbolFlags.EnumMember)) { + if (nameNotFoundMessage && getIsolatedModules(compilerOptions) && !(location.flags & NodeFlags.Ambient) && getSourceFileOfNode(location) !== getSourceFileOfNode(result.valueDeclaration)) { + error( + errorLocation, + Diagnostics.Cannot_access_0_from_another_file_without_qualification_when_1_is_enabled_Use_2_instead, + unescapeLeadingUnderscores(name), + isolatedModulesLikeFlagName, + `${unescapeLeadingUnderscores(getSymbolOfNode(location)!.escapedName)}.${unescapeLeadingUnderscores(name)}`); + } break loop; } break; @@ -36406,7 +36416,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; if (constEnumDeclaration.flags & NodeFlags.Ambient) { - error(node, Diagnostics.Cannot_access_ambient_const_enums_when_the_isolatedModules_flag_is_provided); + error(node, Diagnostics.Cannot_access_ambient_const_enums_when_0_is_enabled, isolatedModulesLikeFlagName); } } } @@ -42322,6 +42332,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inSameLexicalScope(node, mergedClass)) { getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; } + + if (getIsolatedModules(compilerOptions) && !getSourceFileOfNode(node).externalModuleIndicator) { + error(node.name, Diagnostics.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, isolatedModulesLikeFlagName); + } } if (isAmbientExternalModule) { @@ -42522,7 +42536,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, message, symbolToString(symbol)); } - if (compilerOptions.isolatedModules + if (getIsolatedModules(compilerOptions) && !isTypeOnlyImportOrExportDeclaration(node) && !(node.flags & NodeFlags.Ambient)) { const typeOnlyAlias = getTypeOnlyAliasDeclaration(symbol); @@ -42535,8 +42549,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (compilerOptions.preserveValueImports) { Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); const message = isType - ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; + ? compilerOptions.verbatimModuleSyntax + ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled + : compilerOptions.verbatimModuleSyntax + ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), @@ -42545,7 +42563,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ); } if (isType && node.kind === SyntaxKind.ImportEqualsDeclaration && hasEffectiveModifier(node, ModifierFlags.Export)) { - error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_the_isolatedModules_flag_is_provided); + error(node, Diagnostics.Cannot_use_export_import_on_a_type_or_type_only_namespace_when_0_is_enabled, isolatedModulesLikeFlagName); } break; } @@ -42553,16 +42571,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Don't allow re-exporting an export that will be elided when `--isolatedModules` is set. // The exception is that `import type { A } from './a'; export { A }` is allowed // because single-file analysis can determine that the export should be dropped. - if (getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { - const message = isType - ? Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_isolatedModules_is_enabled; + if (compilerOptions.verbatimModuleSyntax || getSourceFileOfNode(typeOnlyAlias) !== getSourceFileOfNode(node)) { const name = idText(node.propertyName || node.name); - addTypeOnlyDeclarationRelatedInfo( - error(node, message, name), - isType ? undefined : typeOnlyAlias, - name - ); + const diagnostic = isType + ? error(node, Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, isolatedModulesLikeFlagName) + : error(node, Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, name, isolatedModulesLikeFlagName); + addTypeOnlyDeclarationRelatedInfo(diagnostic, isType ? undefined : typeOnlyAlias, name); return; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7e63080a32dea..731e251598984 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -907,7 +907,7 @@ "category": "Error", "code": 1277 }, - "Top-level enums 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.": { + "Cannot access '{0}' from another file without qualification when '{1}' is enabled. Use '{2}' instead.": { "category": "Error", "code": 1278 }, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 942a45a78c987..7d39affb7b77f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -4086,21 +4086,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const languageVersion = getEmitScriptTarget(options); const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile); - if (options.isolatedModules) { - if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) { + if (options.isolatedModules || options.verbatimModuleSyntax) { + if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015 && options.isolatedModules) { createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target"); } if (options.preserveConstEnums === false) { - createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_isolatedModules_is_enabled, "preserveConstEnums", "isolatedModules"); - } - - for (const file of files) { - if (!isExternalModule(file) && !isSourceFileJS(file) && !file.isDeclarationFile && file.scriptKind !== ScriptKind.JSON) { - const span = getErrorSpanForNode(file, file); - programDiagnostics.add(createFileDiagnostic(file, span.start, span.length, - 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))); - } + createDiagnosticForOptionName(Diagnostics.Option_preserveConstEnums_cannot_be_disabled_when_0_is_enabled, options.verbatimModuleSyntax ? "verbatimModuleSyntax" : "isolatedModules", "preserveConstEnums"); } } else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) { diff --git a/src/services/codefixes/convertToTypeOnlyExport.ts b/src/services/codefixes/convertToTypeOnlyExport.ts index f6dfc027596d2..b0e67f43b4cbd 100644 --- a/src/services/codefixes/convertToTypeOnlyExport.ts +++ b/src/services/codefixes/convertToTypeOnlyExport.ts @@ -24,7 +24,7 @@ import { registerCodeFix, } from "../_namespaces/ts.codefix"; -const errorCodes = [Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code]; +const errorCodes = [Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type.code]; const fixId = "convertToTypeOnlyExport"; registerCodeFix({ errorCodes, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d9c8599b1a2de..3fe58be45df54 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7105,6 +7105,7 @@ declare namespace ts { types?: string[]; /** Paths used to compute primary types search locations */ typeRoots?: string[]; + verbatimModuleSyntax?: boolean; esModuleInterop?: boolean; useDefineForClassFields?: boolean; [option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index a097a08654da0..f2489f7e62f77 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3172,6 +3172,7 @@ declare namespace ts { types?: string[]; /** Paths used to compute primary types search locations */ typeRoots?: string[]; + verbatimModuleSyntax?: boolean; esModuleInterop?: boolean; useDefineForClassFields?: boolean; [option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined; diff --git a/tests/baselines/reference/config/initTSConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Default initialized TSConfig/tsconfig.json index 19844ec8065fc..1e4cdfe4b4625 100644 --- a/tests/baselines/reference/config/initTSConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Default initialized TSConfig/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --help/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --help/tsconfig.json index 19844ec8065fc..1e4cdfe4b4625 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --help/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --help/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --watch/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --watch/tsconfig.json index 19844ec8065fc..1e4cdfe4b4625 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --watch/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with --watch/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with advanced options/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with advanced options/tsconfig.json index 6e28e016bd11d..89e925953ced5 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with advanced options/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with advanced options/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index d73dbd191a220..cdd0ea5f8b9c2 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index c4c554e65dffb..367ca5521b1cc 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with files options/tsconfig.json index 2368ed9c35291..3f7654b20e7cc 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with files options/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 195f29bcb8708..d0deaa0338887 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 19844ec8065fc..1e4cdfe4b4625 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index fe6fd06aa610a..86cd45a5ee719 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options/tsconfig.json index 12daecbe8ed51..c1e422b17bc59 100644 --- a/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/config/initTSConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -70,6 +70,7 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* 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. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json new file mode 100644 index 0000000000000..5e2760d642d02 --- /dev/null +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "verbatimModuleSyntax": true + } +} diff --git a/tests/baselines/reference/importHelpersInIsolatedModules.errors.txt b/tests/baselines/reference/importHelpersInIsolatedModules.errors.txt deleted file mode 100644 index 0299cb45e097e..0000000000000 --- a/tests/baselines/reference/importHelpersInIsolatedModules.errors.txt +++ /dev/null @@ -1,37 +0,0 @@ -tests/cases/compiler/script.ts(1,1): error TS1208: 'script.ts' 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. - - -==== tests/cases/compiler/external.ts (0 errors) ==== - export class A { } - export class B extends A { } - - declare var dec: any; - - @dec - class C { - method(@dec x: number) { - } - } - -==== tests/cases/compiler/script.ts (1 errors) ==== - class A { } - ~~~~~ -!!! error TS1208: 'script.ts' 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. - class B extends A { } - - declare var dec: any; - - @dec - class C { - method(@dec x: number) { - } - } - -==== tests/cases/compiler/tslib.d.ts (0 errors) ==== - export declare function __extends(d: Function, b: Function): void; - export declare function __assign(t: any, ...sources: any[]): any; - export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; - export declare function __param(paramIndex: number, decorator: Function): Function; - export declare function __metadata(metadataKey: any, metadataValue: any): Function; - export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesAmbientConstEnum.errors.txt b/tests/baselines/reference/isolatedModulesAmbientConstEnum.errors.txt index 6deae7b10e138..512ad7e9af54a 100644 --- a/tests/baselines/reference/isolatedModulesAmbientConstEnum.errors.txt +++ b/tests/baselines/reference/isolatedModulesAmbientConstEnum.errors.txt @@ -1,9 +1,9 @@ -tests/cases/compiler/file1.ts(2,16): error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided. +tests/cases/compiler/file1.ts(2,16): error TS2748: Cannot access ambient const enums when 'isolatedModules' is enabled. ==== tests/cases/compiler/file1.ts (1 errors) ==== declare const enum E { X = 1} export var y = E.X; ~ -!!! error TS2748: Cannot access ambient const enums when the '--isolatedModules' flag is provided. +!!! error TS2748: Cannot access ambient const enums when 'isolatedModules' is enabled. \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesExportImportUninstantiatedNamespace.errors.txt b/tests/baselines/reference/isolatedModulesExportImportUninstantiatedNamespace.errors.txt index f4d14877543d6..90d8dcf9f63f3 100644 --- a/tests/baselines/reference/isolatedModulesExportImportUninstantiatedNamespace.errors.txt +++ b/tests/baselines/reference/isolatedModulesExportImportUninstantiatedNamespace.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/factory.ts(3,1): error TS1269: Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided. +tests/cases/compiler/factory.ts(3,1): error TS1269: Cannot use 'export import' on a type or type-only namespace when 'isolatedModules' is enabled. ==== tests/cases/compiler/jsx.ts (0 errors) ==== @@ -12,7 +12,7 @@ tests/cases/compiler/factory.ts(3,1): error TS1269: Cannot use 'export import' o export import JSX = JSXInternal; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1269: Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided. +!!! error TS1269: Cannot use 'export import' on a type or type-only namespace when 'isolatedModules' is enabled. export function createElement( tagName: string, diff --git a/tests/baselines/reference/isolatedModulesNoExternalModule.errors.txt b/tests/baselines/reference/isolatedModulesNoExternalModule.errors.txt deleted file mode 100644 index 478de41275c61..0000000000000 --- a/tests/baselines/reference/isolatedModulesNoExternalModule.errors.txt +++ /dev/null @@ -1,7 +0,0 @@ -tests/cases/compiler/file1.ts(1,1): error TS1208: 'file1.ts' 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. - - -==== tests/cases/compiler/file1.ts (1 errors) ==== - var x; - ~~~ -!!! error TS1208: 'file1.ts' 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. \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesNoExternalModuleMultiple.errors.txt b/tests/baselines/reference/isolatedModulesNoExternalModuleMultiple.errors.txt deleted file mode 100644 index f728dd626dc30..0000000000000 --- a/tests/baselines/reference/isolatedModulesNoExternalModuleMultiple.errors.txt +++ /dev/null @@ -1,20 +0,0 @@ -tests/cases/compiler/file1.ts(1,1): error TS1208: 'file1.ts' 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. -tests/cases/compiler/file2.ts(1,1): error TS1208: 'file2.ts' 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. -tests/cases/compiler/file3.ts(1,1): error TS1208: 'file3.ts' 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. - - -==== tests/cases/compiler/file1.ts (1 errors) ==== - var x; - ~~~ -!!! error TS1208: 'file1.ts' 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. - -==== tests/cases/compiler/file2.ts (1 errors) ==== - var y; - ~~~ -!!! error TS1208: 'file2.ts' 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. - -==== tests/cases/compiler/file3.ts (1 errors) ==== - var z; - ~~~ -!!! error TS1208: 'file3.ts' 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. - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesOut.errors.txt b/tests/baselines/reference/isolatedModulesOut.errors.txt index ce44a3de5b39d..8f3eb6d71ed5f 100644 --- a/tests/baselines/reference/isolatedModulesOut.errors.txt +++ b/tests/baselines/reference/isolatedModulesOut.errors.txt @@ -1,6 +1,5 @@ error TS5053: Option 'out' cannot be specified with option 'isolatedModules'. tests/cases/compiler/file1.ts(1,1): error TS6131: Cannot compile modules using option 'out' unless the '--module' flag is 'amd' or 'system'. -tests/cases/compiler/file2.ts(1,1): error TS1208: 'file2.ts' 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. !!! error TS5053: Option 'out' cannot be specified with option 'isolatedModules'. @@ -8,7 +7,5 @@ tests/cases/compiler/file2.ts(1,1): error TS1208: 'file2.ts' cannot be compiled export var x; ~~~~~~~~~~~~~ !!! error TS6131: Cannot compile modules using option 'out' unless the '--module' flag is 'amd' or 'system'. -==== tests/cases/compiler/file2.ts (1 errors) ==== - var y; - ~~~ -!!! error TS1208: 'file2.ts' 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. \ No newline at end of file +==== tests/cases/compiler/file2.ts (0 errors) ==== + var y; \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesPlainFile-AMD.errors.txt b/tests/baselines/reference/isolatedModulesPlainFile-AMD.errors.txt deleted file mode 100644 index ca06b74cee0e9..0000000000000 --- a/tests/baselines/reference/isolatedModulesPlainFile-AMD.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/compiler/isolatedModulesPlainFile-AMD.ts(1,1): error TS1208: 'isolatedModulesPlainFile-AMD.ts' 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. - - -==== tests/cases/compiler/isolatedModulesPlainFile-AMD.ts (1 errors) ==== - declare function run(a: number): void; - ~~~~~~~ -!!! error TS1208: 'isolatedModulesPlainFile-AMD.ts' 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. - run(1); - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesPlainFile-CommonJS.errors.txt b/tests/baselines/reference/isolatedModulesPlainFile-CommonJS.errors.txt deleted file mode 100644 index def1c9c5457a0..0000000000000 --- a/tests/baselines/reference/isolatedModulesPlainFile-CommonJS.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/compiler/isolatedModulesPlainFile-CommonJS.ts(1,1): error TS1208: 'isolatedModulesPlainFile-CommonJS.ts' 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. - - -==== tests/cases/compiler/isolatedModulesPlainFile-CommonJS.ts (1 errors) ==== - declare function run(a: number): void; - ~~~~~~~ -!!! error TS1208: 'isolatedModulesPlainFile-CommonJS.ts' 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. - run(1); - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesPlainFile-ES6.errors.txt b/tests/baselines/reference/isolatedModulesPlainFile-ES6.errors.txt deleted file mode 100644 index 12fdb624b6db5..0000000000000 --- a/tests/baselines/reference/isolatedModulesPlainFile-ES6.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/compiler/isolatedModulesPlainFile-ES6.ts(1,1): error TS1208: 'isolatedModulesPlainFile-ES6.ts' 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. - - -==== tests/cases/compiler/isolatedModulesPlainFile-ES6.ts (1 errors) ==== - declare function run(a: number): void; - ~~~~~~~ -!!! error TS1208: 'isolatedModulesPlainFile-ES6.ts' 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. - run(1); - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesPlainFile-System.errors.txt b/tests/baselines/reference/isolatedModulesPlainFile-System.errors.txt deleted file mode 100644 index 5661c88665ce9..0000000000000 --- a/tests/baselines/reference/isolatedModulesPlainFile-System.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/compiler/isolatedModulesPlainFile-System.ts(1,1): error TS1208: 'isolatedModulesPlainFile-System.ts' 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. - - -==== tests/cases/compiler/isolatedModulesPlainFile-System.ts (1 errors) ==== - declare function run(a: number): void; - ~~~~~~~ -!!! error TS1208: 'isolatedModulesPlainFile-System.ts' 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. - run(1); - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesPlainFile-UMD.errors.txt b/tests/baselines/reference/isolatedModulesPlainFile-UMD.errors.txt deleted file mode 100644 index d503d006e35ac..0000000000000 --- a/tests/baselines/reference/isolatedModulesPlainFile-UMD.errors.txt +++ /dev/null @@ -1,9 +0,0 @@ -tests/cases/compiler/isolatedModulesPlainFile-UMD.ts(1,1): error TS1208: 'isolatedModulesPlainFile-UMD.ts' 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. - - -==== tests/cases/compiler/isolatedModulesPlainFile-UMD.ts (1 errors) ==== - declare function run(a: number): void; - ~~~~~~~ -!!! error TS1208: 'isolatedModulesPlainFile-UMD.ts' 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. - run(1); - \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesReExportType.errors.txt b/tests/baselines/reference/isolatedModulesReExportType.errors.txt index f615abd52c7ce..3f88e9d012930 100644 --- a/tests/baselines/reference/isolatedModulesReExportType.errors.txt +++ b/tests/baselines/reference/isolatedModulesReExportType.errors.txt @@ -1,6 +1,6 @@ -/user.ts(2,10): error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. -/user.ts(3,1): error TS1269: Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided. -/user.ts(17,10): error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. +/user.ts(2,10): error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. +/user.ts(3,1): error TS1269: Cannot use 'export import' on a type or type-only namespace when 'isolatedModules' is enabled. +/user.ts(17,10): error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. /user.ts(25,10): error TS1448: 'CC' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled. @@ -8,10 +8,10 @@ // Error, can't re-export something that's only a type. export { T } from "./exportT"; ~ -!!! error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. +!!! error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. export import T2 = require("./exportEqualsT"); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS1269: Cannot use 'export import' on a type or type-only namespace when the '--isolatedModules' flag is provided. +!!! error TS1269: Cannot use 'export import' on a type or type-only namespace when 'isolatedModules' is enabled. // OK, has a value side export { C } from "./exportValue"; @@ -27,7 +27,7 @@ import { T } from "./exportT"; export { T as T4 }; ~~~~~~~ -!!! error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. +!!! error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. // Ok, type-only import indicates that the export can be elided. import type { T as TT } from "./exportT"; diff --git a/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt index 9823c1d1ae459..525ad99a2fc03 100644 --- a/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt +++ b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt @@ -2,7 +2,7 @@ tests/cases/conformance/externalModules/typeOnly/c.ts(1,8): error TS1444: 'Defau tests/cases/conformance/externalModules/typeOnly/c.ts(2,10): error TS1444: 'A' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/c.ts(3,8): error TS1446: 'DefaultB' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/c.ts(4,10): error TS1446: 'B' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. -tests/cases/conformance/externalModules/typeOnly/d.ts(1,10): error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. +tests/cases/conformance/externalModules/typeOnly/d.ts(1,10): error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. tests/cases/conformance/externalModules/typeOnly/d.ts(2,10): error TS1448: 'B' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled. tests/cases/conformance/externalModules/typeOnly/e.ts(1,10): error TS1444: 'AA' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/e.ts(1,14): error TS1446: 'BB' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. @@ -41,7 +41,7 @@ tests/cases/conformance/externalModules/typeOnly/e.ts(1,14): error TS1446: 'BB' ==== tests/cases/conformance/externalModules/typeOnly/d.ts (2 errors) ==== export { A as AA } from "./a"; ~~~~~~~ -!!! error TS1205: Re-exporting a type when the '--isolatedModules' flag is provided requires using 'export type'. +!!! error TS1205: Re-exporting a type when 'isolatedModules' is enabled requires using 'export type'. export { B as BB } from "./b"; ~~~~~~~ !!! error TS1448: 'B' resolves to a type-only declaration and must be re-exported using a type-only re-export when 'isolatedModules' is enabled. diff --git a/tests/baselines/reference/tscWatch/emit/emit-for-configured-projects/should-always-return-the-file-itself-if-'--isolatedModules'-is-specified.js b/tests/baselines/reference/tscWatch/emit/emit-for-configured-projects/should-always-return-the-file-itself-if-'--isolatedModules'-is-specified.js index 941178467ee04..c15f6eae12f03 100644 --- a/tests/baselines/reference/tscWatch/emit/emit-for-configured-projects/should-always-return-the-file-itself-if-'--isolatedModules'-is-specified.js +++ b/tests/baselines/reference/tscWatch/emit/emit-for-configured-projects/should-always-return-the-file-itself-if-'--isolatedModules'-is-specified.js @@ -36,12 +36,7 @@ Output:: >> Screen clear [12:00:23 AM] Starting compilation in watch mode... -a/b/globalFile3.ts:1:1 - error TS1208: 'globalFile3.ts' 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. - -1 interface GlobalFoo { age: number } -  ~~~~~~~~~ - -[12:00:34 AM] Found 1 error. Watching for file changes. +[12:00:34 AM] Found 0 errors. Watching for file changes. @@ -142,12 +137,7 @@ Output:: >> Screen clear [12:00:38 AM] File change detected. Starting incremental compilation... -a/b/globalFile3.ts:1:1 - error TS1208: 'globalFile3.ts' 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. - -1 interface GlobalFoo { age: number } -  ~~~~~~~~~ - -[12:00:42 AM] Found 1 error. Watching for file changes. +[12:00:42 AM] Found 0 errors. Watching for file changes. From cf5c28494bd7d2d354beb13ac24197254a4c0bd6 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 8 Dec 2022 11:20:36 -0800 Subject: [PATCH 03/15] Add tests for loosened isolatedModules script checks --- src/compiler/checker.ts | 45 +++++------ ...ModulesGlobalNamespacesAndEnums.errors.txt | 43 +++++++++++ ...isolatedModulesGlobalNamespacesAndEnums.js | 64 ++++++++++++++++ ...tedModulesGlobalNamespacesAndEnums.symbols | 72 ++++++++++++++++++ ...latedModulesGlobalNamespacesAndEnums.types | 74 +++++++++++++++++++ ...isolatedModulesGlobalNamespacesAndEnums.ts | 34 +++++++++ 6 files changed, 311 insertions(+), 21 deletions(-) create mode 100644 tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt create mode 100644 tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js create mode 100644 tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.symbols create mode 100644 tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.types create mode 100644 tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ad69b5371905f..69ddece624968 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42312,30 +42312,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The following checks only apply on a non-ambient instantiated module declaration. if (symbol.flags & SymbolFlags.ValueModule && !inAmbientContext - && symbol.declarations - && symbol.declarations.length > 1 - && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions))) { - const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); - if (firstNonAmbientClassOrFunc) { - if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); - } - else if (node.pos < firstNonAmbientClassOrFunc.pos) { - error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); - } - } - - // if the module merges with a class declaration in the same lexical scope, - // we need to track this to ensure the correct emit. - const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); - if (mergedClass && - inSameLexicalScope(node, mergedClass)) { - getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; - } - + && isInstantiatedModule(node, shouldPreserveConstEnums(compilerOptions)) + ) { if (getIsolatedModules(compilerOptions) && !getSourceFileOfNode(node).externalModuleIndicator) { + // This could be loosened a little if needed. The only problem we are trying to avoid is unqualified + // references to namespace members declared in other files. But use of namespaces is discouraged anyway, + // so for now we will just not allow them in scripts, which is the only place they can merge cross-file. error(node.name, Diagnostics.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, isolatedModulesLikeFlagName); } + if (symbol.declarations?.length > 1) { + const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); + if (firstNonAmbientClassOrFunc) { + if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { + error(node.name, Diagnostics.A_namespace_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged); + } + else if (node.pos < firstNonAmbientClassOrFunc.pos) { + error(node.name, Diagnostics.A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged); + } + } + + // if the module merges with a class declaration in the same lexical scope, + // we need to track this to ensure the correct emit. + const mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration); + if (mergedClass && + inSameLexicalScope(node, mergedClass)) { + getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; + } + } } if (isAmbientExternalModule) { diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt new file mode 100644 index 0000000000000..9b11e24436e3a --- /dev/null +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt @@ -0,0 +1,43 @@ +tests/cases/compiler/enum2.ts(3,9): error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. +tests/cases/compiler/enum2.ts(4,9): error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. +tests/cases/compiler/script-namespaces.ts(1,11): error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. + + +==== tests/cases/compiler/script-namespaces.ts (1 errors) ==== + namespace Instantiated { + ~~~~~~~~~~~~ +!!! error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. + export const x = 1; + } + namespace Uninstantiated { + export type T = number; + } + declare namespace Ambient { + export const x: number; + } + +==== tests/cases/compiler/module-namespaces.ts (0 errors) ==== + export namespace Instantiated { + export const x = 1; + } + +==== tests/cases/compiler/enum1.ts (0 errors) ==== + enum Enum { A, B, C } + declare enum Enum { X = 1_000_000 } + const d = 'd'; + +==== tests/cases/compiler/enum2.ts (2 errors) ==== + enum Enum { + D = d, + E = A, // error + ~ +!!! error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. + Y = X, // error + ~ +!!! error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. + Z = Enum.A + } + + declare enum Enum { + F = A + } \ No newline at end of file diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js new file mode 100644 index 0000000000000..bf2f2eb3ba238 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts] //// + +//// [script-namespaces.ts] +namespace Instantiated { + export const x = 1; +} +namespace Uninstantiated { + export type T = number; +} +declare namespace Ambient { + export const x: number; +} + +//// [module-namespaces.ts] +export namespace Instantiated { + export const x = 1; +} + +//// [enum1.ts] +enum Enum { A, B, C } +declare enum Enum { X = 1_000_000 } +const d = 'd'; + +//// [enum2.ts] +enum Enum { + D = d, + E = A, // error + Y = X, // error + Z = Enum.A +} + +declare enum Enum { + F = A +} + +//// [script-namespaces.js] +var Instantiated; +(function (Instantiated) { + Instantiated.x = 1; +})(Instantiated || (Instantiated = {})); +//// [module-namespaces.js] +"use strict"; +exports.__esModule = true; +exports.Instantiated = void 0; +var Instantiated; +(function (Instantiated) { + Instantiated.x = 1; +})(Instantiated = exports.Instantiated || (exports.Instantiated = {})); +//// [enum1.js] +var Enum; +(function (Enum) { + Enum[Enum["A"] = 0] = "A"; + Enum[Enum["B"] = 1] = "B"; + Enum[Enum["C"] = 2] = "C"; +})(Enum || (Enum = {})); +var d = 'd'; +//// [enum2.js] +var Enum; +(function (Enum) { + Enum["D"] = "d"; + Enum[Enum["E"] = 0] = "E"; + Enum[Enum["Y"] = 1000000] = "Y"; + Enum[Enum["Z"] = 0] = "Z"; +})(Enum || (Enum = {})); diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.symbols b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.symbols new file mode 100644 index 0000000000000..d08ac0eed7529 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.symbols @@ -0,0 +1,72 @@ +=== tests/cases/compiler/script-namespaces.ts === +namespace Instantiated { +>Instantiated : Symbol(Instantiated, Decl(script-namespaces.ts, 0, 0)) + + export const x = 1; +>x : Symbol(x, Decl(script-namespaces.ts, 1, 16)) +} +namespace Uninstantiated { +>Uninstantiated : Symbol(Uninstantiated, Decl(script-namespaces.ts, 2, 1)) + + export type T = number; +>T : Symbol(T, Decl(script-namespaces.ts, 3, 26)) +} +declare namespace Ambient { +>Ambient : Symbol(Ambient, Decl(script-namespaces.ts, 5, 1)) + + export const x: number; +>x : Symbol(x, Decl(script-namespaces.ts, 7, 16)) +} + +=== tests/cases/compiler/module-namespaces.ts === +export namespace Instantiated { +>Instantiated : Symbol(Instantiated, Decl(module-namespaces.ts, 0, 0)) + + export const x = 1; +>x : Symbol(x, Decl(module-namespaces.ts, 1, 16)) +} + +=== tests/cases/compiler/enum1.ts === +enum Enum { A, B, C } +>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1)) +>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11)) +>B : Symbol(Enum.B, Decl(enum1.ts, 0, 14)) +>C : Symbol(Enum.C, Decl(enum1.ts, 0, 17)) + +declare enum Enum { X = 1_000_000 } +>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1)) +>X : Symbol(Enum.X, Decl(enum1.ts, 1, 19)) + +const d = 'd'; +>d : Symbol(d, Decl(enum1.ts, 2, 5)) + +=== tests/cases/compiler/enum2.ts === +enum Enum { +>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1)) + + D = d, +>D : Symbol(Enum.D, Decl(enum2.ts, 0, 11)) +>d : Symbol(d, Decl(enum1.ts, 2, 5)) + + E = A, // error +>E : Symbol(Enum.E, Decl(enum2.ts, 1, 10)) +>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11)) + + Y = X, // error +>Y : Symbol(Enum.Y, Decl(enum2.ts, 2, 10)) +>X : Symbol(Enum.X, Decl(enum1.ts, 1, 19)) + + Z = Enum.A +>Z : Symbol(Enum.Z, Decl(enum2.ts, 3, 10)) +>Enum.A : Symbol(Enum.A, Decl(enum1.ts, 0, 11)) +>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1)) +>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11)) +} + +declare enum Enum { +>Enum : Symbol(Enum, Decl(enum1.ts, 0, 0), Decl(enum1.ts, 0, 21), Decl(enum2.ts, 0, 0), Decl(enum2.ts, 5, 1)) + + F = A +>F : Symbol(Enum.F, Decl(enum2.ts, 7, 19)) +>A : Symbol(Enum.A, Decl(enum1.ts, 0, 11)) +} diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.types b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.types new file mode 100644 index 0000000000000..5342286cbd827 --- /dev/null +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.types @@ -0,0 +1,74 @@ +=== tests/cases/compiler/script-namespaces.ts === +namespace Instantiated { +>Instantiated : typeof Instantiated + + export const x = 1; +>x : 1 +>1 : 1 +} +namespace Uninstantiated { + export type T = number; +>T : number +} +declare namespace Ambient { +>Ambient : typeof Ambient + + export const x: number; +>x : number +} + +=== tests/cases/compiler/module-namespaces.ts === +export namespace Instantiated { +>Instantiated : typeof Instantiated + + export const x = 1; +>x : 1 +>1 : 1 +} + +=== tests/cases/compiler/enum1.ts === +enum Enum { A, B, C } +>Enum : Enum +>A : Enum.A +>B : Enum.B +>C : Enum.C + +declare enum Enum { X = 1_000_000 } +>Enum : Enum +>X : Enum.X +>1_000_000 : 1000000 + +const d = 'd'; +>d : "d" +>'d' : "d" + +=== tests/cases/compiler/enum2.ts === +enum Enum { +>Enum : Enum + + D = d, +>D : Enum.D +>d : "d" + + E = A, // error +>E : Enum.A +>A : Enum.A + + Y = X, // error +>Y : Enum.X +>X : Enum.X + + Z = Enum.A +>Z : Enum.A +>Enum.A : Enum.A +>Enum : typeof Enum +>A : Enum.A +} + +declare enum Enum { +>Enum : Enum + + F = A +>F : Enum.A +>A : Enum.A +} diff --git a/tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts b/tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts new file mode 100644 index 0000000000000..9a1548da88e77 --- /dev/null +++ b/tests/cases/compiler/isolatedModulesGlobalNamespacesAndEnums.ts @@ -0,0 +1,34 @@ +// @isolatedModules: true + +// @Filename: script-namespaces.ts +namespace Instantiated { + export const x = 1; +} +namespace Uninstantiated { + export type T = number; +} +declare namespace Ambient { + export const x: number; +} + +// @Filename: module-namespaces.ts +export namespace Instantiated { + export const x = 1; +} + +// @Filename: enum1.ts +enum Enum { A, B, C } +declare enum Enum { X = 1_000_000 } +const d = 'd'; + +// @Filename: enum2.ts +enum Enum { + D = d, + E = A, // error + Y = X, // error + Z = Enum.A +} + +declare enum Enum { + F = A +} \ No newline at end of file From a6127464802266a34d03ffbcd6fa75a04a95b1cf Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 8 Dec 2022 14:51:03 -0800 Subject: [PATCH 04/15] Update emit, add test --- src/compiler/checker.ts | 6 ++- src/compiler/transformers/ts.ts | 10 ++-- .../verbatimModuleSyntaxCompat.errors.txt | 14 ++++++ .../verbatimModuleSyntaxNoElision.errors.txt | 34 +++++++++++++ .../verbatimModuleSyntaxNoElision.js | 38 ++++++++++++++ .../verbatimModuleSyntaxNoElision.symbols | 49 ++++++++++++++++++ .../verbatimModuleSyntaxNoElision.types | 50 +++++++++++++++++++ .../verbatimModuleSyntaxCompat.ts | 9 ++++ .../verbatimModuleSyntaxNoElision.ts | 22 ++++++++ 9 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElision.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElision.js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElision.symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElision.types create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat.ts create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 69ddece624968..a4d979269ddf1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42320,7 +42320,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // so for now we will just not allow them in scripts, which is the only place they can merge cross-file. error(node.name, Diagnostics.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, isolatedModulesLikeFlagName); } - if (symbol.declarations?.length > 1) { + if (symbol.declarations?.length! > 1) { const firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol); if (firstNonAmbientClassOrFunc) { if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) { @@ -42549,7 +42549,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportClause: case SyntaxKind.ImportSpecifier: case SyntaxKind.ImportEqualsDeclaration: { - if (compilerOptions.preserveValueImports) { + if (compilerOptions.preserveValueImports || compilerOptions.verbatimModuleSyntax) { Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); const message = isType ? compilerOptions.verbatimModuleSyntax @@ -44514,6 +44514,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isValueAliasDeclaration(node: Node): boolean { + Debug.assert(!compilerOptions.verbatimModuleSyntax); switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: return isAliasResolvedToValue(getSymbolOfNode(node)); @@ -44567,6 +44568,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean { + Debug.assert(!compilerOptions.verbatimModuleSyntax); if (isAliasSymbolDeclaration(node)) { const symbol = getSymbolOfNode(node); const links = symbol && getSymbolLinks(symbol); diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 1b27a345ce67b..c9acee3a9798c 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2217,7 +2217,7 @@ export function transformTypeScript(context: TransformationContext) { } else { // Elide named imports if all of its import specifiers are elided and settings allow. - const allowEmpty = compilerOptions.preserveValueImports && ( + const allowEmpty = compilerOptions.verbatimModuleSyntax || compilerOptions.preserveValueImports && ( compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error); const elements = visitNodes(node.elements, visitImportSpecifier, isImportSpecifier); @@ -2242,7 +2242,7 @@ export function transformTypeScript(context: TransformationContext) { */ function visitExportAssignment(node: ExportAssignment): VisitResult { // Elide the export assignment if it does not reference a value. - return resolver.isValueAliasDeclaration(node) + return compilerOptions.verbatimModuleSyntax || resolver.isValueAliasDeclaration(node) ? visitEachChild(node, visitor, context) : undefined; } @@ -2265,7 +2265,7 @@ export function transformTypeScript(context: TransformationContext) { } // Elide the export declaration if all of its named exports are elided. - const allowEmpty = !!node.moduleSpecifier && ( + const allowEmpty = compilerOptions.verbatimModuleSyntax || !!node.moduleSpecifier && ( compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Preserve || compilerOptions.importsNotUsedAsValues === ImportsNotUsedAsValues.Error); const exportClause = visitNode( @@ -2311,7 +2311,7 @@ export function transformTypeScript(context: TransformationContext) { */ function visitExportSpecifier(node: ExportSpecifier): VisitResult { // Elide an export specifier if it does not reference a value. - return !node.isTypeOnly && resolver.isValueAliasDeclaration(node) ? node : undefined; + return !node.isTypeOnly && (compilerOptions.verbatimModuleSyntax || resolver.isValueAliasDeclaration(node)) ? node : undefined; } /** @@ -2663,7 +2663,7 @@ export function transformTypeScript(context: TransformationContext) { } function shouldEmitAliasDeclaration(node: Node): boolean { - return isInJSFile(node) || + return compilerOptions.verbatimModuleSyntax || isInJSFile(node) || (compilerOptions.preserveValueImports ? resolver.isValueAliasDeclaration(node) : resolver.isReferencedAliasDeclaration(node)); diff --git a/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt new file mode 100644 index 0000000000000..3c2d3441518dc --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt @@ -0,0 +1,14 @@ +error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5096: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +error TS5096: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +error TS5096: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +error TS5097: Option 'verbatimModuleSyntax' cannot be used when 'module' is set to 'UMD', 'AMD', or 'System'. + + +!!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5096: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +!!! error TS5096: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +!!! error TS5096: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +!!! error TS5097: Option 'verbatimModuleSyntax' cannot be used when 'module' is set to 'UMD', 'AMD', or 'System'. +==== tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat.ts (0 errors) ==== + export {}; \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElision.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxNoElision.errors.txt new file mode 100644 index 0000000000000..feee2583483f8 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElision.errors.txt @@ -0,0 +1,34 @@ +/b.ts(1,13): error TS1484: 'A' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +/b.ts(5,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. +/b.ts(6,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. +/c.ts(1,10): error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. + + +==== /a.ts (0 errors) ==== + export const a = 0; + export type A = typeof a; + export class AClass {} + +==== /b.ts (3 errors) ==== + import { a, A, AClass } from "./a"; + ~ +!!! error TS1484: 'A' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. + import type { a as aValue, A as AType } from "./a"; + import { type A as AType2 } from "./a"; + + export { A }; + ~ +!!! error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. + export { A as A2 } from "./a"; + ~~~~~~~ +!!! error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. + export type { A as A3 } from "./a"; + export { type A as A4 } from "./a"; + export type { AClass } from "./a"; + +==== /c.ts (1 errors) ==== + import { AClass } from "./b"; + ~~~~~~ +!!! error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +!!! related TS1377 /b.ts:9:15: 'AClass' was exported here. + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElision.js b/tests/baselines/reference/verbatimModuleSyntaxNoElision.js new file mode 100644 index 0000000000000..b658ff8e6a714 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElision.js @@ -0,0 +1,38 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts] //// + +//// [a.ts] +export const a = 0; +export type A = typeof a; +export class AClass {} + +//// [b.ts] +import { a, A, AClass } from "./a"; +import type { a as aValue, A as AType } from "./a"; +import { type A as AType2 } from "./a"; + +export { A }; +export { A as A2 } from "./a"; +export type { A as A3 } from "./a"; +export { type A as A4 } from "./a"; +export type { AClass } from "./a"; + +//// [c.ts] +import { AClass } from "./b"; + + +//// [a.js] +export var a = 0; +var AClass = /** @class */ (function () { + function AClass() { + } + return AClass; +}()); +export { AClass }; +//// [b.js] +import { a, A, AClass } from "./a"; +import {} from "./a"; +export { A }; +export { A as A2 } from "./a"; +export {} from "./a"; +//// [c.js] +import { AClass } from "./b"; diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElision.symbols b/tests/baselines/reference/verbatimModuleSyntaxNoElision.symbols new file mode 100644 index 0000000000000..8b84501fbed25 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElision.symbols @@ -0,0 +1,49 @@ +=== /a.ts === +export const a = 0; +>a : Symbol(a, Decl(a.ts, 0, 12)) + +export type A = typeof a; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>a : Symbol(a, Decl(a.ts, 0, 12)) + +export class AClass {} +>AClass : Symbol(AClass, Decl(a.ts, 1, 25)) + +=== /b.ts === +import { a, A, AClass } from "./a"; +>a : Symbol(a, Decl(b.ts, 0, 8)) +>A : Symbol(A, Decl(b.ts, 0, 11)) +>AClass : Symbol(AClass, Decl(b.ts, 0, 14)) + +import type { a as aValue, A as AType } from "./a"; +>a : Symbol(a, Decl(a.ts, 0, 12)) +>aValue : Symbol(aValue, Decl(b.ts, 1, 13)) +>A : Symbol(A, Decl(a.ts, 0, 19)) +>AType : Symbol(AType, Decl(b.ts, 1, 26)) + +import { type A as AType2 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>AType2 : Symbol(AType2, Decl(b.ts, 2, 8)) + +export { A }; +>A : Symbol(A, Decl(b.ts, 4, 8)) + +export { A as A2 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A2 : Symbol(A2, Decl(b.ts, 5, 8)) + +export type { A as A3 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A3 : Symbol(A3, Decl(b.ts, 6, 13)) + +export { type A as A4 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A4 : Symbol(A4, Decl(b.ts, 7, 8)) + +export type { AClass } from "./a"; +>AClass : Symbol(AClass, Decl(b.ts, 8, 13)) + +=== /c.ts === +import { AClass } from "./b"; +>AClass : Symbol(AClass, Decl(c.ts, 0, 8)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElision.types b/tests/baselines/reference/verbatimModuleSyntaxNoElision.types new file mode 100644 index 0000000000000..5bea23a96f2a2 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElision.types @@ -0,0 +1,50 @@ +=== /a.ts === +export const a = 0; +>a : 0 +>0 : 0 + +export type A = typeof a; +>A : 0 +>a : 0 + +export class AClass {} +>AClass : AClass + +=== /b.ts === +import { a, A, AClass } from "./a"; +>a : 0 +>A : any +>AClass : typeof AClass + +import type { a as aValue, A as AType } from "./a"; +>a : 0 +>aValue : any +>A : any +>AType : 0 + +import { type A as AType2 } from "./a"; +>A : any +>AType2 : any + +export { A }; +>A : any + +export { A as A2 } from "./a"; +>A : any +>A2 : any + +export type { A as A3 } from "./a"; +>A : any +>A3 : 0 + +export { type A as A4 } from "./a"; +>A : any +>A4 : any + +export type { AClass } from "./a"; +>AClass : AClass + +=== /c.ts === +import { AClass } from "./b"; +>AClass : typeof AClass + diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat.ts new file mode 100644 index 0000000000000..0c280a26530cd --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat.ts @@ -0,0 +1,9 @@ +// @verbatimModuleSyntax: true +// @isolatedModules: true +// @preserveValueImports: true +// @importsNotUsedAsValues: error +// @module: system +// @noEmit: true +// @noTypesAndSymbols: true + +export {}; \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts new file mode 100644 index 0000000000000..074ae5cbffd81 --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts @@ -0,0 +1,22 @@ +// @verbatimModuleSyntax: true +// @module: esnext +// @moduleResolution: node + +// @Filename: /a.ts +export const a = 0; +export type A = typeof a; +export class AClass {} + +// @Filename: /b.ts +import { a, A, AClass } from "./a"; +import type { a as aValue, A as AType } from "./a"; +import { type A as AType2 } from "./a"; + +export { A }; +export { A as A2 } from "./a"; +export type { A as A3 } from "./a"; +export { type A as A4 } from "./a"; +export type { AClass } from "./a"; + +// @Filename: /c.ts +import { AClass } from "./b"; From 7e8dc51ddc445cb8d4764a09afce4eb5e52a3738 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 9 Dec 2022 10:22:52 -0800 Subject: [PATCH 05/15] Add elision tests, restrictions for export= --- src/compiler/checker.ts | 15 +++-- src/compiler/diagnosticMessages.json | 8 +++ ...erbatimModuleSyntaxNoElisionCJS.errors.txt | 44 ++++++++++++++ .../verbatimModuleSyntaxNoElisionCJS.js | 57 +++++++++++++++++++ .../verbatimModuleSyntaxNoElisionCJS.symbols | 54 ++++++++++++++++++ .../verbatimModuleSyntaxNoElisionCJS.types | 50 ++++++++++++++++ .../verbatimModuleSyntaxNoElisionCJS.ts | 35 ++++++++++++ ...ts => verbatimModuleSyntaxNoElisionESM.ts} | 0 8 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.types create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionCJS.ts rename tests/cases/conformance/externalModules/{verbatimModuleSyntaxNoElision.ts => verbatimModuleSyntaxNoElisionESM.ts} (100%) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a4d979269ddf1..7c5ed73673dc7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42931,18 +42931,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (sym) { markAliasReferenced(sym, id); // If not a value, we're interpreting the identifier as a type export, along the lines of (`export { Id as default }`) - const target = sym.flags & SymbolFlags.Alias ? resolveAlias(sym) : sym; - if (getAllSymbolFlags(target) & SymbolFlags.Value) { + if (getAllSymbolFlags(sym) & SymbolFlags.Value) { // However if it is a value, we need to check it's being used correctly - checkExpressionCached(node.expression); + checkExpressionCached(id); + if (compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) { + error(id, Diagnostics.An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, idText(id)); + } + } + else if (compilerOptions.verbatimModuleSyntax) { + error(id, Diagnostics.An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, idText(id)); } } else { - checkExpressionCached(node.expression); // doesn't resolve, check as expression to mark as error + checkExpressionCached(id); // doesn't resolve, check as expression to mark as error } if (getEmitDeclarations(compilerOptions)) { - collectLinkedAliases(node.expression as Identifier, /*setVisibility*/ true); + collectLinkedAliases(id, /*setVisibility*/ true); } } else { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 731e251598984..be2c900f55689 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -911,6 +911,14 @@ "category": "Error", "code": 1278 }, + "An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": { + "category": "Error", + "code": 1279 + }, + "An 'export =' declaration must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": { + "category": "Error", + "code": 1280 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.errors.txt new file mode 100644 index 0000000000000..22d822bcdb461 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.errors.txt @@ -0,0 +1,44 @@ +/a.ts(2,10): error TS1279: An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. +/b.ts(1,1): error TS1484: 'I' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +/d.ts(3,10): error TS1280: An 'export =' declaration must reference a real value when 'verbatimModuleSyntax' is enabled, but 'J' resolves to a type-only declaration. +/e.d.ts(2,10): error TS1279: An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. + + +==== /a.ts (1 errors) ==== + interface I {} + export = I; + ~ +!!! error TS1279: An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. + +==== /b.ts (1 errors) ==== + import I = require("./a"); + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1484: 'I' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. + +==== /c.ts (0 errors) ==== + interface I {} + namespace I { + export const x = 1; + } + export = I; + +==== /d.ts (1 errors) ==== + import I = require("./c"); + import type J = require("./c"); + export = J; + ~ +!!! error TS1280: An 'export =' declaration must reference a real value when 'verbatimModuleSyntax' is enabled, but 'J' resolves to a type-only declaration. + +==== /e.d.ts (1 errors) ==== + interface I {} + export = I; + ~ +!!! error TS1279: An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. + +==== /f.ts (0 errors) ==== + import type I = require("./e"); + const I = {}; + export = I; + +==== /z.ts (0 errors) ==== + // test harness is weird if the last file includs a require >:( \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.js b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.js new file mode 100644 index 0000000000000..f2735943c0a43 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.js @@ -0,0 +1,57 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionCJS.ts] //// + +//// [a.ts] +interface I {} +export = I; + +//// [b.ts] +import I = require("./a"); + +//// [c.ts] +interface I {} +namespace I { + export const x = 1; +} +export = I; + +//// [d.ts] +import I = require("./c"); +import type J = require("./c"); +export = J; + +//// [e.d.ts] +interface I {} +export = I; + +//// [f.ts] +import type I = require("./e"); +const I = {}; +export = I; + +//// [z.ts] +// test harness is weird if the last file includs a require >:( + +//// [a.js] +"use strict"; +module.exports = I; +//// [b.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const I = require("./a"); +//// [c.js] +"use strict"; +var I; +(function (I) { + I.x = 1; +})(I || (I = {})); +module.exports = I; +//// [d.js] +"use strict"; +const I = require("./c"); +module.exports = J; +//// [f.js] +"use strict"; +const I = {}; +module.exports = I; +//// [z.js] +// test harness is weird if the last file includs a require >:( diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.symbols b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.symbols new file mode 100644 index 0000000000000..ad0ecb49ba716 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.symbols @@ -0,0 +1,54 @@ +=== /a.ts === +interface I {} +>I : Symbol(I, Decl(a.ts, 0, 0)) + +export = I; +>I : Symbol(I, Decl(a.ts, 0, 0)) + +=== /b.ts === +import I = require("./a"); +>I : Symbol(I, Decl(b.ts, 0, 0)) + +=== /c.ts === +interface I {} +>I : Symbol(I, Decl(c.ts, 0, 0), Decl(c.ts, 0, 14)) + +namespace I { +>I : Symbol(I, Decl(c.ts, 0, 0), Decl(c.ts, 0, 14)) + + export const x = 1; +>x : Symbol(x, Decl(c.ts, 2, 16)) +} +export = I; +>I : Symbol(I, Decl(c.ts, 0, 0), Decl(c.ts, 0, 14)) + +=== /d.ts === +import I = require("./c"); +>I : Symbol(I, Decl(d.ts, 0, 0)) + +import type J = require("./c"); +>J : Symbol(J, Decl(d.ts, 0, 26)) + +export = J; +>J : Symbol(J, Decl(d.ts, 0, 26)) + +=== /e.d.ts === +interface I {} +>I : Symbol(I, Decl(e.d.ts, 0, 0)) + +export = I; +>I : Symbol(I, Decl(e.d.ts, 0, 0)) + +=== /f.ts === +import type I = require("./e"); +>I : Symbol(I, Decl(f.ts, 0, 0), Decl(f.ts, 1, 5)) + +const I = {}; +>I : Symbol(I, Decl(f.ts, 0, 0), Decl(f.ts, 1, 5)) + +export = I; +>I : Symbol(I, Decl(f.ts, 0, 0), Decl(f.ts, 1, 5)) + +=== /z.ts === + +// test harness is weird if the last file includs a require >:( diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.types b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.types new file mode 100644 index 0000000000000..80b69af9bda79 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionCJS.types @@ -0,0 +1,50 @@ +=== /a.ts === +interface I {} +export = I; +>I : I + +=== /b.ts === +import I = require("./a"); +>I : any + +=== /c.ts === +interface I {} +namespace I { +>I : typeof I + + export const x = 1; +>x : 1 +>1 : 1 +} +export = I; +>I : I + +=== /d.ts === +import I = require("./c"); +>I : typeof I + +import type J = require("./c"); +>J : typeof I + +export = J; +>J : I + +=== /e.d.ts === +interface I {} +export = I; +>I : I + +=== /f.ts === +import type I = require("./e"); +>I : {} + +const I = {}; +>I : {} +>{} : {} + +export = I; +>I : I + +=== /z.ts === + +// test harness is weird if the last file includs a require >:( diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionCJS.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionCJS.ts new file mode 100644 index 0000000000000..989d14d20d632 --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionCJS.ts @@ -0,0 +1,35 @@ +// @verbatimModuleSyntax: true +// @target: esnext +// @module: commonjs +// @moduleResolution: node + +// @Filename: /a.ts +interface I {} +export = I; + +// @Filename: /b.ts +import I = require("./a"); + +// @Filename: /c.ts +interface I {} +namespace I { + export const x = 1; +} +export = I; + +// @Filename: /d.ts +import I = require("./c"); +import type J = require("./c"); +export = J; + +// @Filename: /e.d.ts +interface I {} +export = I; + +// @Filename: /f.ts +import type I = require("./e"); +const I = {}; +export = I; + +// @Filename: /z.ts +// test harness is weird if the last file includs a require >:( \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts similarity index 100% rename from tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElision.ts rename to tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts From 2ebbb974737b047245620a9e7b259ae4181104b4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 9 Dec 2022 16:21:46 -0800 Subject: [PATCH 06/15] Start adding syntax restrictions --- src/compiler/checker.ts | 18 ++++++++--- src/compiler/diagnosticMessages.json | 4 +++ src/compiler/types.ts | 15 ++++++++++ src/compiler/utilities.ts | 21 +++++++++++-- ...tionsESM(esmoduleinterop=false).errors.txt | 23 ++++++++++++++ ...xRestrictionsESM(esmoduleinterop=false).js | 23 ++++++++++++++ ...rictionsESM(esmoduleinterop=false).symbols | 30 +++++++++++++++++++ ...strictionsESM(esmoduleinterop=false).types | 28 +++++++++++++++++ ...ctionsESM(esmoduleinterop=true).errors.txt | 19 ++++++++++++ ...axRestrictionsESM(esmoduleinterop=true).js | 23 ++++++++++++++ ...trictionsESM(esmoduleinterop=true).symbols | 30 +++++++++++++++++++ ...estrictionsESM(esmoduleinterop=true).types | 28 +++++++++++++++++ .../verbatimModuleSyntaxRestrictionsCJS.ts | 21 +++++++++++++ .../verbatimModuleSyntaxRestrictionsESM.ts | 20 +++++++++++++ 14 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).types create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).types create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c5ed73673dc7..3cc1c57508b46 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7,6 +7,7 @@ import { addRange, addRelatedInfo, addSyntheticLeadingComment, + AliasDeclarationNode, AllAccessorDeclarations, and, AnonymousType, @@ -423,6 +424,7 @@ import { isBindableStaticElementAccessExpression, isBindableStaticNameExpression, isBindingElement, + isBindingElementOfBareOrAccessedRequire, isBindingPattern, isBlock, isBlockOrCatchScoped, @@ -39524,8 +39526,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // For a commonjs `const x = require`, validate the alias and exit const symbol = getSymbolOfNode(node); - if (symbol.flags & SymbolFlags.Alias && isVariableDeclarationInitializedToBareOrAccessedRequire(node.kind === SyntaxKind.BindingElement ? node.parent.parent : node)) { - checkAliasSymbol(node as BindingElement | VariableDeclaration); + if (symbol.flags & SymbolFlags.Alias && (isVariableDeclarationInitializedToBareOrAccessedRequire(node) || isBindingElementOfBareOrAccessedRequire(node))) { + checkAliasSymbol(node); return; } @@ -42479,7 +42481,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function checkAliasSymbol(node: ImportEqualsDeclaration | VariableDeclaration | ImportClause | NamespaceImport | ImportSpecifier | ExportSpecifier | NamespaceExport | BindingElement) { + function checkAliasSymbol(node: AliasDeclarationNode) { let symbol = getSymbolOfNode(node); const target = resolveAlias(symbol); @@ -42580,11 +42582,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? error(node, Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type, isolatedModulesLikeFlagName) : error(node, Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_re_exported_using_a_type_only_re_export_when_1_is_enabled, name, isolatedModulesLikeFlagName); addTypeOnlyDeclarationRelatedInfo(diagnostic, isType ? undefined : typeOnlyAlias, name); - return; + break; } } } } + + if (compilerOptions.verbatimModuleSyntax && + node.kind !== SyntaxKind.ImportEqualsDeclaration && + !isInJSFile(node) && + (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { + error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + } } if (isImportSpecifier(node)) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index be2c900f55689..35472c654646b 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -919,6 +919,10 @@ "category": "Error", "code": 1280 }, + "ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1281 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 108c54fa33235..2322c6eb54e6e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5194,6 +5194,21 @@ export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitialize /** @internal */ export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo; +/** @internal */ +export type AliasDeclarationNode = + | ImportEqualsDeclaration + | VariableDeclarationInitializedTo + | ImportClause + | NamespaceImport + | ImportSpecifier + | ExportSpecifier + | NamespaceExport + | BindingElementOfBareOrAccessedRequire; + +/** @internal */ +export type BindingElementOfBareOrAccessedRequire = BindingElement & { parent: { parent: VariableDeclarationInitializedTo } }; + /** @internal */ export type AnyImportOrRequireStatement = AnyImportSyntax | RequireVariableStatement; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 68aab9b889f73..a200b7836fc0b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -28,6 +28,7 @@ import { BindableStaticElementAccessExpression, BindableStaticNameExpression, BindingElement, + BindingElementOfBareOrAccessedRequire, Block, BundleFileSection, BundleFileSectionKind, @@ -190,8 +191,8 @@ import { getTrailingCommentRanges, HasExpressionInitializer, hasExtension, - HasInitializer, hasInitializer, + HasInitializer, HasJSDoc, hasJSDocNodes, HasModifiers, @@ -224,6 +225,7 @@ import { isArrowFunction, isBigIntLiteral, isBinaryExpression, + isBindingElement, isBindingPattern, isCallExpression, isClassDeclaration, @@ -518,6 +520,7 @@ import { WriteFileCallback, WriteFileCallbackData, YieldExpression, + AliasDeclarationNode, } from "./_namespaces/ts"; /** @internal */ @@ -2967,6 +2970,11 @@ export function isVariableDeclarationInitializedToBareOrAccessedRequire(node: No return isVariableDeclarationInitializedWithRequireHelper(node, /*allowAccessedRequire*/ true); } +/** @internal */ +export function isBindingElementOfBareOrAccessedRequire(node: Node): node is BindingElementOfBareOrAccessedRequire { + return isBindingElement(node) && isVariableDeclarationInitializedToBareOrAccessedRequire(node.parent.parent); +} + function isVariableDeclarationInitializedWithRequireHelper(node: Node, allowAccessedRequire: boolean) { return isVariableDeclaration(node) && !!node.initializer && @@ -3387,14 +3395,23 @@ export function isFunctionSymbol(symbol: Symbol | undefined) { } /** @internal */ -export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire): StringLiteralLike | undefined { +export function tryGetModuleSpecifierFromDeclaration(node: AnyImportOrBareOrAccessedRequire | AliasDeclarationNode): StringLiteralLike | undefined { switch (node.kind) { case SyntaxKind.VariableDeclaration: + case SyntaxKind.BindingElement: return findAncestor(node.initializer, (node): node is RequireOrImportCall => isRequireCall(node, /*requireStringLiteralLikeArgument*/ true))?.arguments[0]; case SyntaxKind.ImportDeclaration: return tryCast(node.moduleSpecifier, isStringLiteralLike); case SyntaxKind.ImportEqualsDeclaration: return tryCast(tryCast(node.moduleReference, isExternalModuleReference)?.expression, isStringLiteralLike); + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceExport: + return tryCast(node.parent.moduleSpecifier, isStringLiteralLike); + case SyntaxKind.NamespaceImport: + case SyntaxKind.ExportSpecifier: + return tryCast(node.parent.parent.moduleSpecifier, isStringLiteralLike); + case SyntaxKind.ImportSpecifier: + return tryCast(node.parent.parent.parent.moduleSpecifier, isStringLiteralLike); default: Debug.assertNever(node); } diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).errors.txt b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).errors.txt new file mode 100644 index 0000000000000..b8003fc5d3937 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).errors.txt @@ -0,0 +1,23 @@ +/main.ts(1,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. +/main.ts(3,8): error TS1259: Module '"/decl"' can only be default-imported using the 'allowSyntheticDefaultImports' flag + + +==== /main.ts (2 errors) ==== + import CJSy = require("./decl"); // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. + import type CJSy2 = require("./decl"); // ok I guess? + import CJSy3 from "./decl"; // ok in esModuleInterop + ~~~~~ +!!! error TS1259: Module '"/decl"' can only be default-imported using the 'allowSyntheticDefaultImports' flag +!!! related TS2594 /decl.d.ts:2:1: This module is declared with 'export =', and can only be used with a default import when using the 'allowSyntheticDefaultImports' flag. + import * as types from "./types"; // ok + CJSy; +==== /decl.d.ts (0 errors) ==== + declare class CJSy {} + export = CJSy; + +==== /types.ts (0 errors) ==== + interface Typey {} + export type { Typey }; + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).js b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).js new file mode 100644 index 0000000000000..9246ef5022e26 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts] //// + +//// [decl.d.ts] +declare class CJSy {} +export = CJSy; + +//// [types.ts] +interface Typey {} +export type { Typey }; + +//// [main.ts] +import CJSy = require("./decl"); // error +import type CJSy2 = require("./decl"); // ok I guess? +import CJSy3 from "./decl"; // ok in esModuleInterop +import * as types from "./types"; // ok +CJSy; + +//// [types.js] +export {}; +//// [main.js] +import CJSy3 from "./decl"; // ok in esModuleInterop +import * as types from "./types"; // ok +CJSy; diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).symbols b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).symbols new file mode 100644 index 0000000000000..e96a383ec42d1 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).symbols @@ -0,0 +1,30 @@ +=== /main.ts === +import CJSy = require("./decl"); // error +>CJSy : Symbol(CJSy, Decl(main.ts, 0, 0)) + +import type CJSy2 = require("./decl"); // ok I guess? +>CJSy2 : Symbol(CJSy2, Decl(main.ts, 0, 32)) + +import CJSy3 from "./decl"; // ok in esModuleInterop +>CJSy3 : Symbol(CJSy3, Decl(main.ts, 2, 6)) + +import * as types from "./types"; // ok +>types : Symbol(types, Decl(main.ts, 3, 6)) + +CJSy; +>CJSy : Symbol(CJSy, Decl(main.ts, 0, 0)) + +=== /decl.d.ts === +declare class CJSy {} +>CJSy : Symbol(CJSy, Decl(decl.d.ts, 0, 0)) + +export = CJSy; +>CJSy : Symbol(CJSy, Decl(decl.d.ts, 0, 0)) + +=== /types.ts === +interface Typey {} +>Typey : Symbol(Typey, Decl(types.ts, 0, 0)) + +export type { Typey }; +>Typey : Symbol(Typey, Decl(types.ts, 1, 13)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).types b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).types new file mode 100644 index 0000000000000..145ea2afc846c --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=false).types @@ -0,0 +1,28 @@ +=== /main.ts === +import CJSy = require("./decl"); // error +>CJSy : typeof CJSy + +import type CJSy2 = require("./decl"); // ok I guess? +>CJSy2 : typeof CJSy + +import CJSy3 from "./decl"; // ok in esModuleInterop +>CJSy3 : any + +import * as types from "./types"; // ok +>types : typeof types + +CJSy; +>CJSy : typeof CJSy + +=== /decl.d.ts === +declare class CJSy {} +>CJSy : CJSy + +export = CJSy; +>CJSy : CJSy + +=== /types.ts === +interface Typey {} +export type { Typey }; +>Typey : Typey + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).errors.txt b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).errors.txt new file mode 100644 index 0000000000000..7a6b23e911e0f --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).errors.txt @@ -0,0 +1,19 @@ +/main.ts(1,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. + + +==== /main.ts (1 errors) ==== + import CJSy = require("./decl"); // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. + import type CJSy2 = require("./decl"); // ok I guess? + import CJSy3 from "./decl"; // ok in esModuleInterop + import * as types from "./types"; // ok + CJSy; +==== /decl.d.ts (0 errors) ==== + declare class CJSy {} + export = CJSy; + +==== /types.ts (0 errors) ==== + interface Typey {} + export type { Typey }; + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).js b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).js new file mode 100644 index 0000000000000..9246ef5022e26 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).js @@ -0,0 +1,23 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts] //// + +//// [decl.d.ts] +declare class CJSy {} +export = CJSy; + +//// [types.ts] +interface Typey {} +export type { Typey }; + +//// [main.ts] +import CJSy = require("./decl"); // error +import type CJSy2 = require("./decl"); // ok I guess? +import CJSy3 from "./decl"; // ok in esModuleInterop +import * as types from "./types"; // ok +CJSy; + +//// [types.js] +export {}; +//// [main.js] +import CJSy3 from "./decl"; // ok in esModuleInterop +import * as types from "./types"; // ok +CJSy; diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).symbols b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).symbols new file mode 100644 index 0000000000000..e96a383ec42d1 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).symbols @@ -0,0 +1,30 @@ +=== /main.ts === +import CJSy = require("./decl"); // error +>CJSy : Symbol(CJSy, Decl(main.ts, 0, 0)) + +import type CJSy2 = require("./decl"); // ok I guess? +>CJSy2 : Symbol(CJSy2, Decl(main.ts, 0, 32)) + +import CJSy3 from "./decl"; // ok in esModuleInterop +>CJSy3 : Symbol(CJSy3, Decl(main.ts, 2, 6)) + +import * as types from "./types"; // ok +>types : Symbol(types, Decl(main.ts, 3, 6)) + +CJSy; +>CJSy : Symbol(CJSy, Decl(main.ts, 0, 0)) + +=== /decl.d.ts === +declare class CJSy {} +>CJSy : Symbol(CJSy, Decl(decl.d.ts, 0, 0)) + +export = CJSy; +>CJSy : Symbol(CJSy, Decl(decl.d.ts, 0, 0)) + +=== /types.ts === +interface Typey {} +>Typey : Symbol(Typey, Decl(types.ts, 0, 0)) + +export type { Typey }; +>Typey : Symbol(Typey, Decl(types.ts, 1, 13)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).types b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).types new file mode 100644 index 0000000000000..821e720badb88 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsESM(esmoduleinterop=true).types @@ -0,0 +1,28 @@ +=== /main.ts === +import CJSy = require("./decl"); // error +>CJSy : typeof CJSy + +import type CJSy2 = require("./decl"); // ok I guess? +>CJSy2 : typeof CJSy + +import CJSy3 from "./decl"; // ok in esModuleInterop +>CJSy3 : typeof CJSy + +import * as types from "./types"; // ok +>types : typeof types + +CJSy; +>CJSy : typeof CJSy + +=== /decl.d.ts === +declare class CJSy {} +>CJSy : CJSy + +export = CJSy; +>CJSy : CJSy + +=== /types.ts === +interface Typey {} +export type { Typey }; +>Typey : Typey + diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts new file mode 100644 index 0000000000000..dee6016bf5d4e --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts @@ -0,0 +1,21 @@ +// @verbatimModuleSyntax: true +// @target: esnext +// @module: commonjs +// @moduleResolution: node +// @esModuleInterop: true + +// @Filename: /decl.d.ts +declare function esmy(): void; +export default esmy; +export declare function funciton(): void; + +// @Filename: /main.ts +import esmy from "./decl"; // error +import * as esmy2 from "./decl"; // error +import { funciton } from "./decl"; // error +import type { funciton as funciton2 } from "./decl"; // ok I guess? +import("./decl"); // error +type T = typeof import("./decl"); // ok +export {}; // error +export const x = 1; // error +export interface I {} // ok diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts new file mode 100644 index 0000000000000..dcc87bdb4a244 --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsESM.ts @@ -0,0 +1,20 @@ +// @verbatimModuleSyntax: true +// @target: esnext +// @module: esnext +// @moduleResolution: node +// @esModuleInterop: true, false + +// @Filename: /decl.d.ts +declare class CJSy {} +export = CJSy; + +// @Filename: /types.ts +interface Typey {} +export type { Typey }; + +// @Filename: /main.ts +import CJSy = require("./decl"); // error +import type CJSy2 = require("./decl"); // ok I guess? +import CJSy3 from "./decl"; // ok in esModuleInterop +import * as types from "./types"; // ok +CJSy; \ No newline at end of file From 5095a7efd6df67dfc3e2addbc9c753fc0c028d4d Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 12 Dec 2022 12:28:13 -0800 Subject: [PATCH 07/15] Finish(?) syntax restrictions --- src/compiler/checker.ts | 14 ++++ src/compiler/diagnosticMessages.json | 4 + ...erbatimModuleSyntaxNoElisionESM.errors.txt | 34 +++++++++ .../verbatimModuleSyntaxNoElisionESM.js | 38 ++++++++++ .../verbatimModuleSyntaxNoElisionESM.symbols | 49 ++++++++++++ .../verbatimModuleSyntaxNoElisionESM.types | 50 +++++++++++++ ...atimModuleSyntaxRestrictionsCJS.errors.txt | 47 ++++++++++++ .../verbatimModuleSyntaxRestrictionsCJS.js | 75 +++++++++++++++++++ ...erbatimModuleSyntaxRestrictionsCJS.symbols | 60 +++++++++++++++ .../verbatimModuleSyntaxRestrictionsCJS.types | 60 +++++++++++++++ .../verbatimModuleSyntaxRestrictionsCJS.ts | 12 +++ 11 files changed, 443 insertions(+) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cc1c57508b46..a3743425b7b65 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -45553,6 +45553,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.ExportKeyword: + if (compilerOptions.verbatimModuleSyntax && + !(node.flags & NodeFlags.Ambient) && + node.kind !== SyntaxKind.TypeAliasDeclaration && + node.kind !== SyntaxKind.InterfaceDeclaration && + node.parent.kind === SyntaxKind.SourceFile && + (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) + ) { + return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_can_only_be_used_on_type_aliases_and_interfaces_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + } + if (flags & ModifierFlags.Export) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export"); } @@ -47063,6 +47073,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkGrammarImportCallExpression(node: ImportCall): boolean { + if (compilerOptions.verbatimModuleSyntax && moduleKind === ModuleKind.CommonJS) { + return grammarErrorOnNode(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + } + if (moduleKind === ModuleKind.ES2015) { return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_are_only_supported_when_the_module_flag_is_set_to_es2020_es2022_esnext_commonjs_amd_system_umd_node16_or_nodenext); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 35472c654646b..f90e3730c5e25 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -923,6 +923,10 @@ "category": "Error", "code": 1281 }, + "A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1282 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt new file mode 100644 index 0000000000000..feee2583483f8 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt @@ -0,0 +1,34 @@ +/b.ts(1,13): error TS1484: 'A' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +/b.ts(5,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. +/b.ts(6,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. +/c.ts(1,10): error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. + + +==== /a.ts (0 errors) ==== + export const a = 0; + export type A = typeof a; + export class AClass {} + +==== /b.ts (3 errors) ==== + import { a, A, AClass } from "./a"; + ~ +!!! error TS1484: 'A' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. + import type { a as aValue, A as AType } from "./a"; + import { type A as AType2 } from "./a"; + + export { A }; + ~ +!!! error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. + export { A as A2 } from "./a"; + ~~~~~~~ +!!! error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. + export type { A as A3 } from "./a"; + export { type A as A4 } from "./a"; + export type { AClass } from "./a"; + +==== /c.ts (1 errors) ==== + import { AClass } from "./b"; + ~~~~~~ +!!! error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +!!! related TS1377 /b.ts:9:15: 'AClass' was exported here. + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js new file mode 100644 index 0000000000000..38b5791c09db6 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js @@ -0,0 +1,38 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts] //// + +//// [a.ts] +export const a = 0; +export type A = typeof a; +export class AClass {} + +//// [b.ts] +import { a, A, AClass } from "./a"; +import type { a as aValue, A as AType } from "./a"; +import { type A as AType2 } from "./a"; + +export { A }; +export { A as A2 } from "./a"; +export type { A as A3 } from "./a"; +export { type A as A4 } from "./a"; +export type { AClass } from "./a"; + +//// [c.ts] +import { AClass } from "./b"; + + +//// [a.js] +export var a = 0; +var AClass = /** @class */ (function () { + function AClass() { + } + return AClass; +}()); +export { AClass }; +//// [b.js] +import { a, A, AClass } from "./a"; +import {} from "./a"; +export { A }; +export { A as A2 } from "./a"; +export {} from "./a"; +//// [c.js] +import { AClass } from "./b"; diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols new file mode 100644 index 0000000000000..8b84501fbed25 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols @@ -0,0 +1,49 @@ +=== /a.ts === +export const a = 0; +>a : Symbol(a, Decl(a.ts, 0, 12)) + +export type A = typeof a; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>a : Symbol(a, Decl(a.ts, 0, 12)) + +export class AClass {} +>AClass : Symbol(AClass, Decl(a.ts, 1, 25)) + +=== /b.ts === +import { a, A, AClass } from "./a"; +>a : Symbol(a, Decl(b.ts, 0, 8)) +>A : Symbol(A, Decl(b.ts, 0, 11)) +>AClass : Symbol(AClass, Decl(b.ts, 0, 14)) + +import type { a as aValue, A as AType } from "./a"; +>a : Symbol(a, Decl(a.ts, 0, 12)) +>aValue : Symbol(aValue, Decl(b.ts, 1, 13)) +>A : Symbol(A, Decl(a.ts, 0, 19)) +>AType : Symbol(AType, Decl(b.ts, 1, 26)) + +import { type A as AType2 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>AType2 : Symbol(AType2, Decl(b.ts, 2, 8)) + +export { A }; +>A : Symbol(A, Decl(b.ts, 4, 8)) + +export { A as A2 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A2 : Symbol(A2, Decl(b.ts, 5, 8)) + +export type { A as A3 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A3 : Symbol(A3, Decl(b.ts, 6, 13)) + +export { type A as A4 } from "./a"; +>A : Symbol(A, Decl(a.ts, 0, 19)) +>A4 : Symbol(A4, Decl(b.ts, 7, 8)) + +export type { AClass } from "./a"; +>AClass : Symbol(AClass, Decl(b.ts, 8, 13)) + +=== /c.ts === +import { AClass } from "./b"; +>AClass : Symbol(AClass, Decl(c.ts, 0, 8)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types new file mode 100644 index 0000000000000..5bea23a96f2a2 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types @@ -0,0 +1,50 @@ +=== /a.ts === +export const a = 0; +>a : 0 +>0 : 0 + +export type A = typeof a; +>A : 0 +>a : 0 + +export class AClass {} +>AClass : AClass + +=== /b.ts === +import { a, A, AClass } from "./a"; +>a : 0 +>A : any +>AClass : typeof AClass + +import type { a as aValue, A as AType } from "./a"; +>a : 0 +>aValue : any +>A : any +>AType : 0 + +import { type A as AType2 } from "./a"; +>A : any +>AType2 : any + +export { A }; +>A : any + +export { A as A2 } from "./a"; +>A : any +>A2 : any + +export type { A as A3 } from "./a"; +>A : any +>A3 : 0 + +export { type A as A4 } from "./a"; +>A : any +>A4 : any + +export type { AClass } from "./a"; +>AClass : AClass + +=== /c.ts === +import { AClass } from "./b"; +>AClass : typeof AClass + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt new file mode 100644 index 0000000000000..0bb4032fcf0fe --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt @@ -0,0 +1,47 @@ +/main.ts(1,8): error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(2,13): error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(3,10): error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(5,1): error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(8,1): error TS1282: A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main2.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. + + +==== /decl.d.ts (0 errors) ==== + declare function esmy(): void; + export default esmy; + export declare function funciton(): void; + +==== /main.ts (5 errors) ==== + import esmy from "./decl"; // error + ~~~~ +!!! error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + import * as esmy2 from "./decl"; // error + ~~~~~ +!!! error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + import { funciton } from "./decl"; // error + ~~~~~~~~ +!!! error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + import type { funciton as funciton2 } from "./decl"; // ok I guess? + import("./decl"); // error + ~~~~~~~~~~~~~~~~ +!!! error TS1281: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + type T = typeof import("./decl"); // ok + export {}; // error + export const x = 1; // error + ~~~~~~ +!!! error TS1282: A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled. + export interface I {} // ok + export type { T }; // ok + +==== /main2.ts (1 errors) ==== + export interface I {} + export = { x: 1 }; + ~~~~~~~~~~~~~~~~~~ +!!! error TS2309: An export assignment cannot be used in a module with other exported elements. + +==== /main3.ts (0 errors) ==== + namespace ns { + export const x = 1; + export interface I {} + } + export = ns; \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js new file mode 100644 index 0000000000000..34e20f57b2364 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js @@ -0,0 +1,75 @@ +//// [tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts] //// + +//// [decl.d.ts] +declare function esmy(): void; +export default esmy; +export declare function funciton(): void; + +//// [main.ts] +import esmy from "./decl"; // error +import * as esmy2 from "./decl"; // error +import { funciton } from "./decl"; // error +import type { funciton as funciton2 } from "./decl"; // ok I guess? +import("./decl"); // error +type T = typeof import("./decl"); // ok +export {}; // error +export const x = 1; // error +export interface I {} // ok +export type { T }; // ok + +//// [main2.ts] +export interface I {} +export = { x: 1 }; + +//// [main3.ts] +namespace ns { + export const x = 1; + export interface I {} +} +export = ns; + +//// [main.js] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.x = void 0; +const decl_1 = __importDefault(require("./decl")); // error +const esmy2 = __importStar(require("./decl")); // error +const decl_2 = require("./decl"); // error +Promise.resolve().then(() => __importStar(require("./decl"))); // error +exports.x = 1; // error +//// [main2.js] +"use strict"; +module.exports = { x: 1 }; +//// [main3.js] +"use strict"; +var ns; +(function (ns) { + ns.x = 1; +})(ns || (ns = {})); +module.exports = ns; diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols new file mode 100644 index 0000000000000..a68231ac91e78 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols @@ -0,0 +1,60 @@ +=== /decl.d.ts === +declare function esmy(): void; +>esmy : Symbol(esmy, Decl(decl.d.ts, 0, 0)) + +export default esmy; +>esmy : Symbol(esmy, Decl(decl.d.ts, 0, 0)) + +export declare function funciton(): void; +>funciton : Symbol(funciton, Decl(decl.d.ts, 1, 20)) + +=== /main.ts === +import esmy from "./decl"; // error +>esmy : Symbol(esmy, Decl(main.ts, 0, 6)) + +import * as esmy2 from "./decl"; // error +>esmy2 : Symbol(esmy2, Decl(main.ts, 1, 6)) + +import { funciton } from "./decl"; // error +>funciton : Symbol(funciton, Decl(main.ts, 2, 8)) + +import type { funciton as funciton2 } from "./decl"; // ok I guess? +>funciton : Symbol(esmy2.funciton, Decl(decl.d.ts, 1, 20)) +>funciton2 : Symbol(funciton2, Decl(main.ts, 3, 13)) + +import("./decl"); // error +>"./decl" : Symbol("/decl", Decl(decl.d.ts, 0, 0)) + +type T = typeof import("./decl"); // ok +>T : Symbol(T, Decl(main.ts, 4, 17)) + +export {}; // error +export const x = 1; // error +>x : Symbol(x, Decl(main.ts, 7, 12)) + +export interface I {} // ok +>I : Symbol(I, Decl(main.ts, 7, 19)) + +export type { T }; // ok +>T : Symbol(T, Decl(main.ts, 9, 13)) + +=== /main2.ts === +export interface I {} +>I : Symbol(I, Decl(main2.ts, 0, 0)) + +export = { x: 1 }; +>x : Symbol(x, Decl(main2.ts, 1, 10)) + +=== /main3.ts === +namespace ns { +>ns : Symbol(ns, Decl(main3.ts, 0, 0)) + + export const x = 1; +>x : Symbol(x, Decl(main3.ts, 1, 16)) + + export interface I {} +>I : Symbol(I, Decl(main3.ts, 1, 23)) +} +export = ns; +>ns : Symbol(ns, Decl(main3.ts, 0, 0)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types new file mode 100644 index 0000000000000..0d4cb520bf80e --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types @@ -0,0 +1,60 @@ +=== /decl.d.ts === +declare function esmy(): void; +>esmy : () => void + +export default esmy; +>esmy : () => void + +export declare function funciton(): void; +>funciton : () => void + +=== /main.ts === +import esmy from "./decl"; // error +>esmy : () => void + +import * as esmy2 from "./decl"; // error +>esmy2 : typeof esmy2 + +import { funciton } from "./decl"; // error +>funciton : () => void + +import type { funciton as funciton2 } from "./decl"; // ok I guess? +>funciton : () => void +>funciton2 : any + +import("./decl"); // error +>import("./decl") : Promise +>"./decl" : "./decl" + +type T = typeof import("./decl"); // ok +>T : typeof import("/decl") + +export {}; // error +export const x = 1; // error +>x : 1 +>1 : 1 + +export interface I {} // ok +export type { T }; // ok +>T : typeof import("/decl") + +=== /main2.ts === +export interface I {} +export = { x: 1 }; +>{ x: 1 } : { x: number; } +>x : number +>1 : 1 + +=== /main3.ts === +namespace ns { +>ns : typeof ns + + export const x = 1; +>x : 1 +>1 : 1 + + export interface I {} +} +export = ns; +>ns : typeof ns + diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts index dee6016bf5d4e..fa7202b56a775 100644 --- a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts @@ -19,3 +19,15 @@ type T = typeof import("./decl"); // ok export {}; // error export const x = 1; // error export interface I {} // ok +export type { T }; // ok + +// @Filename: /main2.ts +export interface I {} +export = { x: 1 }; + +// @Filename: /main3.ts +namespace ns { + export const x = 1; + export interface I {} +} +export = ns; \ No newline at end of file From 0095a8ee404b39d864fdbc652c16027d530907b7 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 12 Dec 2022 13:00:27 -0800 Subject: [PATCH 08/15] Update other references to compilerOptions.isolatedModules --- src/compiler/checker.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a3743425b7b65..4f5a5806de2f5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27027,7 +27027,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // An alias resolving to a const enum cannot be elided if (1) 'isolatedModules' is enabled // (because the const enum value will not be inlined), or if (2) the alias is an export // of a const enum declaration that will be preserved. - if (compilerOptions.isolatedModules || + if (getIsolatedModules(compilerOptions) || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(location) || !isConstEnumOrConstEnumOnlyModule(getExportSymbolOfValueSymbolIfExported(target)) ) { @@ -30619,7 +30619,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 1. if 'isolatedModules' is enabled, because the const enum value will not be inlined, and // 2. if 'preserveConstEnums' is enabled and the expression is itself an export, e.g. `export = Foo.Bar.Baz`. if (isIdentifier(left) && parentSymbol && ( - compilerOptions.isolatedModules || + getIsolatedModules(compilerOptions) || !(prop && (isConstEnumOrConstEnumOnlyModule(prop) || prop.flags & SymbolFlags.EnumMember && node.parent.kind === SyntaxKind.EnumMember)) || shouldPreserveConstEnums(compilerOptions) && isExportOrExportExpression(node) )) { @@ -36414,7 +36414,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { error(node, Diagnostics.const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment_or_type_query); } - if (compilerOptions.isolatedModules) { + if (getIsolatedModules(compilerOptions)) { Debug.assert(!!(type.symbol.flags & SymbolFlags.ConstEnum)); const constEnumDeclaration = type.symbol.valueDeclaration as EnumDeclaration; if (constEnumDeclaration.flags & NodeFlags.Ambient) { @@ -38455,7 +38455,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { markAliasSymbolAsReferenced(rootSymbol); } else if (forDecoratorMetadata - && compilerOptions.isolatedModules + && getIsolatedModules(compilerOptions) && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015 && !symbolIsValue(rootSymbol) && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration)) { From 915c78026907222fe0432b3a2a410ab87ec751d8 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 16 Dec 2022 15:39:11 -0800 Subject: [PATCH 09/15] Auto-imports for CJS files --- src/harness/fourslashImpl.ts | 58 ++++++- src/services/codefixes/importFixes.ts | 142 ++++++++++-------- src/services/completions.ts | 17 +-- src/services/exportInfoMap.ts | 17 ++- .../autoImportVerbatimCJS1.baseline.md | 99 ++++++++++++ .../cases/fourslash/autoImportVerbatimCJS1.ts | 29 ++++ .../codeFixConvertToTypeOnlyExport1.ts | 2 +- .../codeFixConvertToTypeOnlyExport2.ts | 2 +- tests/cases/fourslash/fourslash.ts | 2 +- 9 files changed, 280 insertions(+), 88 deletions(-) create mode 100644 tests/baselines/reference/autoImportVerbatimCJS1.baseline.md create mode 100644 tests/cases/fourslash/autoImportVerbatimCJS1.ts diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 0f35cf2549a84..f99724f6288cf 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3109,9 +3109,9 @@ export class TestState { // Undo changes to perform next fix const span = change.textChanges[0].span; - const deletedText = originalContent.substr(span.start, change.textChanges[0].span.length); - const insertedText = change.textChanges[0].newText; - this.editScriptAndUpdateMarkers(fileName, span.start, span.start + insertedText.length, deletedText); + const deletedText = originalContent.substr(span.start, change.textChanges[0].span.length); + const insertedText = change.textChanges[0].newText; + this.editScriptAndUpdateMarkers(fileName, span.start, span.start + insertedText.length, deletedText); } if (expectedTextArray.length !== actualTextArray.length) { this.raiseError(`Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}:\n\n${actualTextArray.join("\n\n" + "-".repeat(20) + "\n\n")}`); @@ -3197,7 +3197,7 @@ export class TestState { } } - public baselineAutoImports(markerName: string, preferences?: ts.UserPreferences) { + public baselineAutoImports(markerName: string, fullNamesForCodeFix?: string[], preferences?: ts.UserPreferences) { const marker = this.getMarkerByName(markerName); const baselineFile = this.getBaselineFileNameForContainingTestFile(`.baseline.md`); const completionPreferences = { @@ -3208,10 +3208,12 @@ export class TestState { ...preferences }; - const ext = ts.getAnyExtensionFromPath(this.activeFile.fileName).slice(1); + this.goToMarker(marker); + this.configure(completionPreferences); + const fileName = this.activeFile.fileName; + const ext = ts.getAnyExtensionFromPath(fileName).slice(1); const lang = ["mts", "cts"].includes(ext) ? "ts" : ext; let baselineText = codeFence(this.renderMarkers([{ text: "|", fileName: marker.fileName, position: marker.position }], /*useTerminalBoldSequence*/ false), lang) + "\n\n"; - this.goToMarker(marker); const completions = this.getCompletionListAtCaret(completionPreferences)!; @@ -3235,7 +3237,36 @@ export class TestState { }); } - // TODO: do codefixes too + if (fullNamesForCodeFix) { + const scriptInfo = this.languageServiceAdapterHost.getScriptInfo(fileName)!; + const originalContent = scriptInfo.content; + const range = this.getRangesInFile()[0] + || getRangeOfIdentifierTouchingPosition(this.activeFile.content, marker.position) + || { pos: marker.position, end: marker.position }; + + baselineText += `## From codefixes\n\n`; + for (const fullNameForCodeFix of fullNamesForCodeFix) { + this.applyEdits(fileName, [{ span: { start: 0, length: this.getFileContent(fileName).length }, newText: originalContent }]); + this.applyEdits(fileName, [{ span: ts.createTextSpanFromRange(range), newText: fullNameForCodeFix }]); + baselineText += `### When marker text is \`${fullNameForCodeFix}\`\n\n`; + + const codeFixes = this.getCodeFixes(fileName, /*errorCode*/ undefined, completionPreferences) + .filter(f => f.fixName === ts.codefix.importFixName); + for (const fix of codeFixes) { + baselineText += fix.description + "\n"; + if (fix.fixAllDescription) { + baselineText += `Fix all available: ${fix.fixAllDescription}\n`; + } + ts.Debug.assert(fix.changes.length === 1); + const change = ts.first(fix.changes); + ts.Debug.assert(change.fileName === fileName); + this.applyEdits(change.fileName, change.textChanges); + const text = this.getFileContent(fileName); + baselineText += "\n" + codeFence(text, lang) + "\n\n"; + } + } + } + Harness.Baseline.runBaseline(baselineFile, baselineText); } @@ -4687,3 +4718,16 @@ function highlightDifferenceBetweenStrings(source: string, target: string) { function codeFence(code: string, lang?: string) { return `\`\`\`${lang || ""}\n${code}\n\`\`\``; } + +function getRangeOfIdentifierTouchingPosition(content: string, position: number): ts.TextRange | undefined { + const scanner = ts.createScanner(ts.ScriptTarget.Latest, /*skipTrivia*/ true, ts.LanguageVariant.Standard, content); + while (scanner.scan() !== ts.SyntaxKind.EndOfFileToken) { + const tokenStart = scanner.getStartPos(); + if (scanner.getToken() === ts.SyntaxKind.Identifier && tokenStart <= position && scanner.getTextPos() >= position) { + return { pos: tokenStart, end: scanner.getTextPos() }; + } + if (tokenStart > position) { + break; + } + } +} diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index ac89579ab0ed5..d3da6ff7e76e1 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -22,7 +22,6 @@ import { Diagnostics, DiagnosticWithLocation, emptyArray, - escapeLeadingUnderscores, every, ExportKind, factory, @@ -34,6 +33,7 @@ import { formatting, getAllowSyntheticDefaultImports, getBaseFileName, + getDefaultExportInfoWorker, getDefaultLikeExportInfo, getDirectoryPath, getEmitModuleKind, @@ -232,7 +232,7 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu const symbol = checker.getMergedSymbol(skipAlias(exportedSymbol, checker)); const exportInfo = getAllExportInfoForSymbol(sourceFile, symbol, symbolName, /*isJsxTagName*/ false, program, host, preferences, cancellationToken); const useRequire = shouldUseRequire(sourceFile, program); - const fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), moduleSymbol, program, /*useNamespaceInfo*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences); + const fix = getImportFixForSymbol(sourceFile, Debug.checkDefined(exportInfo), moduleSymbol, program, /*position*/ undefined, !!isValidTypeOnlyUseSite, useRequire, host, preferences); if (fix) { addImport({ fix, symbolName, errorIdentifierText: undefined }); } @@ -392,7 +392,6 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu export interface ImportSpecifierResolver { getModuleSpecifierForBestExportInfo( exportInfo: readonly SymbolExportInfo[], - symbolName: string, position: number, isValidTypeOnlyUseSite: boolean, fromCacheOnly?: boolean @@ -407,14 +406,13 @@ export function createImportSpecifierResolver(importingFile: SourceFile, program function getModuleSpecifierForBestExportInfo( exportInfo: readonly SymbolExportInfo[], - symbolName: string, position: number, isValidTypeOnlyUseSite: boolean, fromCacheOnly?: boolean, ): { exportInfo?: SymbolExportInfo, moduleSpecifier: string, computedWithoutCacheCount: number } | undefined { const { fixes, computedWithoutCacheCount } = getImportFixes( exportInfo, - { symbolName, position }, + position, isValidTypeOnlyUseSite, /*useRequire*/ false, program, @@ -448,14 +446,16 @@ interface ImportFixBase { readonly exportInfo?: SymbolExportInfo; readonly moduleSpecifier: string; } -interface FixUseNamespaceImport extends ImportFixBase { - readonly kind: ImportFixKind.UseNamespace; +interface Qualification { + readonly usagePosition: number; readonly namespacePrefix: string; - readonly position: number; +} +interface FixUseNamespaceImport extends ImportFixBase, Qualification { + readonly kind: ImportFixKind.UseNamespace; } interface FixAddJsdocTypeImport extends ImportFixBase { readonly kind: ImportFixKind.JsdocTypeImport; - readonly position: number; + readonly usagePosition: number; readonly isReExport: boolean; readonly exportInfo: SymbolExportInfo; } @@ -470,6 +470,7 @@ interface FixAddNewImport extends ImportFixBase { readonly importKind: ImportKind; readonly addAsTypeOnly: AddAsTypeOnly; readonly useRequire: boolean; + readonly qualification?: Qualification; } interface FixPromoteTypeOnlyImport { readonly kind: ImportFixKind.PromoteTypeOnly; @@ -508,7 +509,7 @@ export function getImportCompletionAction( Debug.assertIsDefined(exportInfos); const useRequire = shouldUseRequire(sourceFile, program); const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(getTokenAtPosition(sourceFile, position)); - const fix = Debug.checkDefined(getImportFixForSymbol(sourceFile, exportInfos, moduleSymbol, program, { symbolName, position }, isValidTypeOnlyUseSite, useRequire, host, preferences)); + const fix = Debug.checkDefined(getImportFixForSymbol(sourceFile, exportInfos, moduleSymbol, program, position, isValidTypeOnlyUseSite, useRequire, host, preferences)); return { moduleSpecifier: fix.moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix( @@ -531,10 +532,10 @@ export function getPromoteTypeOnlyCompletionAction(sourceFile: SourceFile, symbo return fix && codeFixActionToCodeAction(codeActionForFix({ host, formatContext, preferences }, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences)); } -function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], moduleSymbol: Symbol, program: Program, useNamespaceInfo: { position: number, symbolName: string } | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) { +function getImportFixForSymbol(sourceFile: SourceFile, exportInfos: readonly SymbolExportInfo[], moduleSymbol: Symbol, program: Program, position: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, preferences: UserPreferences) { Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol || info.symbol.parent === moduleSymbol), "Some exportInfo should match the specified moduleSymbol"); const packageJsonImportFilter = createPackageJsonImportFilter(sourceFile, preferences, host); - return getBestFix(getImportFixes(exportInfos, useNamespaceInfo, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes, sourceFile, program, packageJsonImportFilter, host); + return getBestFix(getImportFixes(exportInfos, position, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes, sourceFile, program, packageJsonImportFilter, host); } function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction { @@ -574,11 +575,7 @@ function getSingleExportInfoForSymbol(symbol: Symbol, moduleSymbol: Symbol, prog function getImportFixes( exportInfos: readonly SymbolExportInfo[], - useNamespaceInfo: { - symbolName: string, - position: number, - } | undefined, - /** undefined only for missing JSX namespace */ + usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, program: Program, @@ -590,7 +587,7 @@ function getImportFixes( ): { computedWithoutCacheCount: number, fixes: readonly ImportFixWithModuleSpecifier[] } { const checker = program.getTypeChecker(); const existingImports = flatMap(exportInfos, importMap.getImportsForExportInfo); - const useNamespace = useNamespaceInfo && tryUseExistingNamespaceImport(existingImports, useNamespaceInfo.symbolName, useNamespaceInfo.position, checker); + const useNamespace = usagePosition !== undefined && tryUseExistingNamespaceImport(existingImports, usagePosition); const addToExisting = tryAddToExistingImport(existingImports, isValidTypeOnlyUseSite, checker, program.getCompilerOptions()); if (addToExisting) { // Don't bother providing an action to add a new import if we can add to an existing one. @@ -605,7 +602,7 @@ function getImportFixes( existingImports, program, sourceFile, - useNamespaceInfo?.position, + usagePosition, isValidTypeOnlyUseSite, useRequire, host, @@ -617,7 +614,7 @@ function getImportFixes( }; } -function tryUseExistingNamespaceImport(existingImports: readonly FixAddToExistingImportInfo[], symbolName: string, position: number, checker: TypeChecker): FixUseNamespaceImport | undefined { +function tryUseExistingNamespaceImport(existingImports: readonly FixAddToExistingImportInfo[], position: number): FixUseNamespaceImport | undefined { // It is possible that multiple import statements with the same specifier exist in the file. // e.g. // @@ -630,32 +627,16 @@ function tryUseExistingNamespaceImport(existingImports: readonly FixAddToExistin // 1. change "member3" to "ns.member3" // 2. add "member3" to the second import statement's import list // and it is up to the user to decide which one fits best. - return firstDefined(existingImports, ({ declaration }): FixUseNamespaceImport | undefined => { + return firstDefined(existingImports, ({ declaration, importKind }): FixUseNamespaceImport | undefined => { + if (importKind !== ImportKind.Named) return undefined; const namespacePrefix = getNamespaceLikeImportText(declaration); - const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(declaration)?.text; - if (namespacePrefix && moduleSpecifier) { - const moduleSymbol = getTargetModuleFromNamespaceLikeImport(declaration, checker); - if (moduleSymbol && moduleSymbol.exports!.has(escapeLeadingUnderscores(symbolName))) { - return { kind: ImportFixKind.UseNamespace, namespacePrefix, position, moduleSpecifier }; - } + const moduleSpecifier = namespacePrefix && tryGetModuleSpecifierFromDeclaration(declaration)?.text; + if (moduleSpecifier) { + return { kind: ImportFixKind.UseNamespace, namespacePrefix, usagePosition: position, moduleSpecifier }; } }); } -function getTargetModuleFromNamespaceLikeImport(declaration: AnyImportOrRequire, checker: TypeChecker) { - switch (declaration.kind) { - case SyntaxKind.VariableDeclaration: - return checker.resolveExternalModuleName(declaration.initializer.arguments[0]); - case SyntaxKind.ImportEqualsDeclaration: - return checker.getAliasedSymbol(declaration.symbol); - case SyntaxKind.ImportDeclaration: - const namespaceImport = tryCast(declaration.importClause?.namedBindings, isNamespaceImport); - return namespaceImport && checker.getAliasedSymbol(namespaceImport.symbol); - default: - return Debug.assertNever(declaration); - } -} - function getNamespaceLikeImportText(declaration: AnyImportOrRequire) { switch (declaration.kind) { case SyntaxKind.VariableDeclaration: @@ -804,7 +785,7 @@ function createGetChecker(program: Program, host: LanguageServiceHost) { function getNewImportFixes( program: Program, sourceFile: SourceFile, - position: number | undefined, + usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, exportInfo: readonly SymbolExportInfo[], @@ -829,20 +810,45 @@ function getNewImportFixes( const importedSymbolHasValueMeaning = !!(exportInfo.targetFlags & SymbolFlags.Value); const addAsTypeOnly = getAddAsTypeOnly(isValidTypeOnlyUseSite, /*isForNewImportDeclaration*/ true, exportInfo.symbol, exportInfo.targetFlags, checker, compilerOptions); computedWithoutCacheCount += computedWithoutCache ? 1 : 0; - return mapDefined(moduleSpecifiers, (moduleSpecifier): FixAddNewImport | FixAddJsdocTypeImport | undefined => - rejectNodeModulesRelativePaths && pathContainsNodeModules(moduleSpecifier) ? undefined : - // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. - !importedSymbolHasValueMeaning && isJs && position !== undefined ? { kind: ImportFixKind.JsdocTypeImport, moduleSpecifier, position, exportInfo, isReExport: i > 0 } : - { + return mapDefined(moduleSpecifiers, (moduleSpecifier): FixAddNewImport | FixAddJsdocTypeImport | undefined => { + if (rejectNodeModulesRelativePaths && pathContainsNodeModules(moduleSpecifier)) { + return undefined; + } + if (!importedSymbolHasValueMeaning && isJs && usagePosition !== undefined) { + // `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types. + return { kind: ImportFixKind.JsdocTypeImport, moduleSpecifier, usagePosition, exportInfo, isReExport: i > 0 }; + } + const importKind = getImportKind(sourceFile, exportInfo.exportKind, compilerOptions); + let qualification: Qualification | undefined; + if (usagePosition !== undefined && importKind === ImportKind.CommonJS && exportInfo.exportKind === ExportKind.Named) { + // Compiler options are restricting our import options to a require, but we need to access + // a named export or property of the exporting module. We need to import the entire module + // and insert a property access, e.g. `writeFile` becomes + // + // import fs = require("fs"); // or const in JS + // fs.writeFile + const exportEquals = checker.resolveExternalModuleSymbol(exportInfo.moduleSymbol); + let namespacePrefix; + if (exportEquals !== exportInfo.moduleSymbol) { + namespacePrefix = getDefaultExportInfoWorker(exportEquals, checker, compilerOptions)?.name; + } + namespacePrefix ||= moduleSymbolToValidIdentifier( + exportInfo.moduleSymbol, + getEmitScriptTarget(compilerOptions), + /*forceCapitalize*/ false); + qualification = { namespacePrefix, usagePosition }; + } + return { kind: ImportFixKind.AddNew, moduleSpecifier, - importKind: getImportKind(sourceFile, exportInfo.exportKind, compilerOptions), + importKind, useRequire, addAsTypeOnly, exportInfo, isReExport: i > 0, - } - ); + qualification, + }; + }); }); return { computedWithoutCacheCount, fixes }; @@ -853,7 +859,7 @@ function getFixesForAddImport( existingImports: readonly FixAddToExistingImportInfo[], program: Program, sourceFile: SourceFile, - position: number | undefined, + usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, host: LanguageServiceHost, @@ -861,7 +867,7 @@ function getFixesForAddImport( fromCacheOnly?: boolean, ): { computedWithoutCacheCount?: number, fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[] } { const existingDeclaration = firstDefined(existingImports, info => newImportInfoFromExistingSpecifier(info, isValidTypeOnlyUseSite, useRequire, program.getTypeChecker(), program.getCompilerOptions())); - return existingDeclaration ? { fixes: [existingDeclaration] } : getNewImportFixes(program, sourceFile, position, isValidTypeOnlyUseSite, useRequire, exportInfos, host, preferences, fromCacheOnly); + return existingDeclaration ? { fixes: [existingDeclaration] } : getNewImportFixes(program, sourceFile, usagePosition, isValidTypeOnlyUseSite, useRequire, exportInfos, host, preferences, fromCacheOnly); } function newImportInfoFromExistingSpecifier( @@ -991,8 +997,13 @@ function getFixesInfoForUMDImport({ sourceFile, program, host, preferences }: Co const symbolName = umdSymbol.name; const exportInfo: readonly SymbolExportInfo[] = [{ symbol: umdSymbol, moduleSymbol: symbol, moduleFileName: undefined, exportKind: ExportKind.UMD, targetFlags: symbol.flags, isFromPackageJson: false }]; const useRequire = shouldUseRequire(sourceFile, program); - const position = isIdentifier(token) ? token.getStart(sourceFile) : undefined; - const fixes = getImportFixes(exportInfo, position ? { position, symbolName } : undefined, /*isValidTypeOnlyUseSite*/ false, useRequire, program, sourceFile, host, preferences).fixes; + // `usagePosition` is undefined because `token` may not actually be a usage of the symbol we're importing. + // For example, we might need to import `React` in order to use an arbitrary JSX tag. We could send a position + // for other UMD imports, but `usagePosition` is currently only used to insert a namespace qualification + // before a named import, like converting `writeFile` to `fs.writeFile` (whether `fs` is already imported or + // not), and this function will only be called for UMD symbols, which are necessarily an `export =`, not a + // named export. + const fixes = getImportFixes(exportInfo, /*usagePosition*/ undefined, /*isValidTypeOnlyUseSite*/ false, useRequire, program, sourceFile, host, preferences).fixes; return fixes.map(fix => ({ fix, symbolName, errorIdentifierText: tryCast(token, isIdentifier)?.text })); } function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { @@ -1014,6 +1025,10 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { * @internal */ export function getImportKind(importingFile: SourceFile, exportKind: ExportKind, compilerOptions: CompilerOptions, forceImportKeyword?: boolean): ImportKind { + if (compilerOptions.verbatimModuleSyntax && (getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS || importingFile.impliedNodeFormat === ModuleKind.CommonJS)) { + // TODO: if the exporting file is ESM under nodenext, or `forceImport` is given in a JS file, this is impossible + return ImportKind.CommonJS; + } switch (exportKind) { case ExportKind.Named: return ImportKind.Named; case ExportKind.Default: return ImportKind.Default; @@ -1067,7 +1082,7 @@ function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, h const useRequire = shouldUseRequire(sourceFile, program); const exportInfo = getExportInfos(symbolName, isJSXTagName(symbolToken), getMeaningFromLocation(symbolToken), cancellationToken, sourceFile, program, useAutoImportProvider, host, preferences); const fixes = arrayFrom(flatMapIterator(exportInfo.entries(), ([_, exportInfos]) => - getImportFixes(exportInfos, { symbolName, position: symbolToken.getStart(sourceFile) }, isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes)); + getImportFixes(exportInfos, symbolToken.getStart(sourceFile), isValidTypeOnlyUseSite, useRequire, program, sourceFile, host, preferences).fixes)); return fixes.map(fix => ({ fix, symbolName, errorIdentifierText: symbolToken.text, isJsxNamespaceFix: symbolName !== symbolToken.text })); }); } @@ -1136,7 +1151,7 @@ function getExportInfos( const compilerOptions = program.getCompilerOptions(); const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions); - if (defaultInfo && (defaultInfo.name === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, getEmitScriptTarget(compilerOptions), isJsxTagName) === symbolName) && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) { + if (defaultInfo && (defaultInfo.name === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, getEmitScriptTarget(compilerOptions), isJsxTagName) === symbolName) && symbolHasMeaning(defaultInfo.resolvedSymbol, currentTokenMeaning)) { addSymbol(moduleSymbol, sourceFile, defaultInfo.symbol, defaultInfo.exportKind, program, isFromPackageJson); } @@ -1210,12 +1225,17 @@ function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: : [Diagnostics.Update_import_from_0, moduleSpecifierWithoutQuotes]; } case ImportFixKind.AddNew: { - const { importKind, moduleSpecifier, addAsTypeOnly, useRequire } = fix; + const { importKind, moduleSpecifier, addAsTypeOnly, useRequire, qualification } = fix; const getDeclarations = useRequire ? getNewRequires : getNewImports; const defaultImport: Import | undefined = importKind === ImportKind.Default ? { name: symbolName, addAsTypeOnly } : undefined; const namedImports: Import[] | undefined = importKind === ImportKind.Named ? [{ name: symbolName, addAsTypeOnly }] : undefined; - const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS ? { importKind, name: symbolName, addAsTypeOnly } : undefined; + const namespaceLikeImport = importKind === ImportKind.Namespace || importKind === ImportKind.CommonJS + ? { importKind, name: qualification?.namespacePrefix || symbolName, addAsTypeOnly } + : undefined; insertImports(changes, sourceFile, getDeclarations(moduleSpecifier, quotePreference, defaultImport, namedImports, namespaceLikeImport), /*blankLineBetween*/ true); + if (qualification) { + addNamespaceQualifier(changes, sourceFile, qualification); + } return includeSymbolNameInDescription ? [Diagnostics.Import_0_from_1, symbolName, moduleSpecifier] : [Diagnostics.Add_import_from_0, moduleSpecifier]; @@ -1413,11 +1433,11 @@ function doAddExistingFix( } } -function addNamespaceQualifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { namespacePrefix, position }: FixUseNamespaceImport): void { - changes.insertText(sourceFile, position, namespacePrefix + "."); +function addNamespaceQualifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { namespacePrefix, usagePosition }: Qualification): void { + changes.insertText(sourceFile, usagePosition, namespacePrefix + "."); } -function addImportType(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { moduleSpecifier, position }: FixAddJsdocTypeImport, quotePreference: QuotePreference): void { +function addImportType(changes: textChanges.ChangeTracker, sourceFile: SourceFile, { moduleSpecifier, usagePosition: position }: FixAddJsdocTypeImport, quotePreference: QuotePreference): void { changes.insertText(sourceFile, position, getImportTypePrefix(moduleSpecifier, quotePreference)); } diff --git a/src/services/completions.ts b/src/services/completions.ts index 45c25e900c2ce..497e47bd60c47 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -87,7 +87,6 @@ import { getLineAndCharacterOfPosition, getLineStartPositionForPosition, getLocalSymbolForExportDefault, - getNameForExportedSymbol, getNameOfDeclaration, getNameTable, getNewLineCharacter, @@ -556,7 +555,7 @@ const enum KeywordCompletionFilters { const enum GlobalsSearch { Continue, Success, Fail } interface ModuleSpecifierResolutionContext { - tryResolve: (exportInfo: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean) => ModuleSpecifierResolutionResult; + tryResolve: (exportInfo: readonly SymbolExportInfo[], isFromAmbientModule: boolean) => ModuleSpecifierResolutionResult; resolvedAny: () => boolean; skippedAny: () => boolean; resolvedBeyondLimit: () => boolean; @@ -604,9 +603,9 @@ function resolvingModuleSpecifiers( host.log?.(`${logPrefix}: ${timestamp() - start}`); return result; - function tryResolve(exportInfo: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean): ModuleSpecifierResolutionResult { + function tryResolve(exportInfo: readonly SymbolExportInfo[], isFromAmbientModule: boolean): ModuleSpecifierResolutionResult { if (isFromAmbientModule) { - const result = resolver.getModuleSpecifierForBestExportInfo(exportInfo, symbolName, position, isValidTypeOnlyUseSite); + const result = resolver.getModuleSpecifierForBestExportInfo(exportInfo, position, isValidTypeOnlyUseSite); if (result) { ambientCount++; } @@ -615,7 +614,7 @@ function resolvingModuleSpecifiers( const shouldResolveModuleSpecifier = needsFullResolution || preferences.allowIncompleteCompletions && resolvedCount < moduleSpecifierResolutionLimit; const shouldGetModuleSpecifierFromCache = !shouldResolveModuleSpecifier && preferences.allowIncompleteCompletions && cacheAttemptCount < moduleSpecifierResolutionCacheAttemptLimit; const result = (shouldResolveModuleSpecifier || shouldGetModuleSpecifierFromCache) - ? resolver.getModuleSpecifierForBestExportInfo(exportInfo, symbolName, position, isValidTypeOnlyUseSite, shouldGetModuleSpecifierFromCache) + ? resolver.getModuleSpecifierForBestExportInfo(exportInfo, position, isValidTypeOnlyUseSite, shouldGetModuleSpecifierFromCache) : undefined; if (!shouldResolveModuleSpecifier && !shouldGetModuleSpecifierFromCache || shouldGetModuleSpecifierFromCache && !result) { @@ -777,7 +776,7 @@ function continuePreviousIncompleteResponse( const { origin } = Debug.checkDefined(getAutoImportSymbolFromCompletionEntryData(entry.name, entry.data, program, host)); const info = exportMap.get(file.path, entry.data.exportMapKey); - const result = info && context.tryResolve(info, entry.name, !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name))); + const result = info && context.tryResolve(info, !isExternalModuleNameRelative(stripQuotes(origin.moduleSymbol.name))); if (result === "skipped") return entry; if (!result || result === "failed") { host.log?.(`Unexpected failure resolving auto import for '${entry.name}' from '${entry.source}'`); @@ -2508,7 +2507,7 @@ function getCompletionEntryCodeActionsAndSourceDisplay( targetSymbol, moduleSymbol, sourceFile, - getNameForExportedSymbol(symbol, getEmitScriptTarget(compilerOptions), isJsxOpeningTagName), + name, isJsxOpeningTagName, host, program, @@ -3175,7 +3174,7 @@ function getCompletionData( moduleSymbol, symbol: firstAccessibleSymbol, targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags, - }], firstAccessibleSymbol.name, position, isValidTypeOnlyAliasUseSite(location)) || {}; + }], position, isValidTypeOnlyAliasUseSite(location)) || {}; if (moduleSpecifier) { const origin: SymbolOriginInfoResolvedExport = { @@ -3497,7 +3496,7 @@ function getCompletionData( // N.B. in this resolution mode we always try to resolve module specifiers here, // because we have to know now if it's going to fail so we can omit the completion // from the list. - const result = context.tryResolve(info, symbolName, isFromAmbientModule) || {}; + const result = context.tryResolve(info, isFromAmbientModule) || {}; if (result === "failed") return; // If we skipped resolving module specifiers, our selection of which ExportInfo diff --git a/src/services/exportInfoMap.ts b/src/services/exportInfoMap.ts index ffd9501b5db25..d08bc6487e648 100644 --- a/src/services/exportInfoMap.ts +++ b/src/services/exportInfoMap.ts @@ -428,14 +428,14 @@ export function forEachExternalModuleToImportFrom( } function forEachExternalModule(checker: TypeChecker, allSourceFiles: readonly SourceFile[], excludePatterns: readonly RegExp[] | undefined, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) { - const isExcluded = (fileName: string) => excludePatterns?.some(p => p.test(fileName)); + const isExcluded = excludePatterns && ((fileName: string) => excludePatterns.some(p => p.test(fileName))); for (const ambient of checker.getAmbientModules()) { - if (!stringContains(ambient.name, "*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded(d.getSourceFile().fileName)))) { + if (!stringContains(ambient.name, "*") && !(excludePatterns && ambient.declarations?.every(d => isExcluded!(d.getSourceFile().fileName)))) { cb(ambient, /*sourceFile*/ undefined); } } for (const sourceFile of allSourceFiles) { - if (isExternalOrCommonJsModule(sourceFile) && !isExcluded(sourceFile.fileName)) { + if (isExternalOrCommonJsModule(sourceFile) && !isExcluded?.(sourceFile.fileName)) { cb(checker.getMergedSymbol(sourceFile.symbol), sourceFile); } } @@ -526,12 +526,13 @@ function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): if (defaultExport) return { symbol: defaultExport, exportKind: ExportKind.Default }; } -function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined { +/** @internal */ +export function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly resolvedSymbol: Symbol, readonly name: string } | undefined { const localSymbol = getLocalSymbolForExportDefault(defaultExport); - if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name }; + if (localSymbol) return { resolvedSymbol: localSymbol, name: localSymbol.name }; const name = getNameForExportDefault(defaultExport); - if (name !== undefined) return { symbolForMeaning: defaultExport, name }; + if (name !== undefined) return { resolvedSymbol: defaultExport, name }; if (defaultExport.flags & SymbolFlags.Alias) { const aliased = checker.getImmediateAliasedSymbol(defaultExport); @@ -546,9 +547,9 @@ function getDefaultExportInfoWorker(defaultExport: Symbol, checker: TypeChecker, if (defaultExport.escapedName !== InternalSymbolName.Default && defaultExport.escapedName !== InternalSymbolName.ExportEquals) { - return { symbolForMeaning: defaultExport, name: defaultExport.getName() }; + return { resolvedSymbol: defaultExport, name: defaultExport.getName() }; } - return { symbolForMeaning: defaultExport, name: getNameForExportedSymbol(defaultExport, compilerOptions.target) }; + return { resolvedSymbol: defaultExport, name: getNameForExportedSymbol(defaultExport, compilerOptions.target) }; } function getNameForExportDefault(symbol: Symbol): string | undefined { diff --git a/tests/baselines/reference/autoImportVerbatimCJS1.baseline.md b/tests/baselines/reference/autoImportVerbatimCJS1.baseline.md new file mode 100644 index 0000000000000..a1058a67d5904 --- /dev/null +++ b/tests/baselines/reference/autoImportVerbatimCJS1.baseline.md @@ -0,0 +1,99 @@ +```ts +// @Filename: /a.ts +/*|*/ +``` + +## From completions + +- `coolName` from `"./cool-name"` +- `explode` from `"./cool-name"` +- `isAbsolute` from `"path"` +- `join` from `"path"` +- `normalize` from `"path"` +- `path` from `"path"` +- `resolve` from `"path"` + +```ts +import coolName = require("./cool-name"); + +coolName +``` + +```ts +import coolName = require("./cool-name"); + +coolName.explode +``` + +```ts +import path = require("path"); + +path.isAbsolute +``` + +```ts +import path = require("path"); + +path.join +``` + +```ts +import path = require("path"); + +path.normalize +``` + +```ts +import path = require("path"); + +path +``` + +```ts +import path = require("path"); + +path.resolve +``` + +## From codefixes + +### When marker text is `normalize` + +Add import from "path" + +```ts +import path = require("path"); + +path.normalize +``` + +### When marker text is `join` + +Add import from "path" + +```ts +import path = require("path"); + +path.join +``` + +### When marker text is `path` + +Add import from "path" + +```ts +import path = require("path"); + +path +``` + +### When marker text is `explode` + +Add import from "./cool-name" + +```ts +import coolName = require("./cool-name"); + +coolName.explode +``` + diff --git a/tests/cases/fourslash/autoImportVerbatimCJS1.ts b/tests/cases/fourslash/autoImportVerbatimCJS1.ts new file mode 100644 index 0000000000000..dc2b8177d007a --- /dev/null +++ b/tests/cases/fourslash/autoImportVerbatimCJS1.ts @@ -0,0 +1,29 @@ +/// + +// @module: nodenext +// @verbatimModuleSyntax: true +// @allowJs: true + +// @Filename: /node_modules/@types/node/path.d.ts +//// declare module 'path' { +//// namespace path { +//// interface PlatformPath { +//// normalize(p: string): string; +//// join(...paths: string[]): string; +//// resolve(...pathSegments: string[]): string; +//// isAbsolute(p: string): boolean; +//// } +//// } +//// const path: path.PlatformPath; +//// export = path; +//// } + +// @Filename: /cool-name.js +//// module.exports = { +//// explode: () => {} +//// } + +// @Filename: /a.ts +//// /**/ + +verify.baselineAutoImports("", ["normalize", "join", "path", "explode"]); diff --git a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts index df2d1be4279d6..36e2c77334860 100644 --- a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts +++ b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport1.ts @@ -14,7 +14,7 @@ goTo.file("/b.ts"); verify.codeFix({ index: 0, description: ts.Diagnostics.Convert_to_type_only_export.message, - errorCode: ts.Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code, + errorCode: ts.Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type.code, newFileContent: `/* Comment */ export type { A, B } from './a';` diff --git a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts index 16733b082ab04..d2489fc567384 100644 --- a/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts +++ b/tests/cases/fourslash/codeFixConvertToTypeOnlyExport2.ts @@ -14,7 +14,7 @@ goTo.file("/b.ts"); verify.codeFix({ index: 0, description: ts.Diagnostics.Convert_to_type_only_export.message, - errorCode: ts.Diagnostics.Re_exporting_a_type_when_the_isolatedModules_flag_is_provided_requires_using_export_type.code, + errorCode: ts.Diagnostics.Re_exporting_a_type_when_0_is_enabled_requires_using_export_type.code, newFileContent: `export { B } from './a'; export type { A, C } from './a'; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 262d2327d2ffc..a19ea116325b8 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -375,7 +375,7 @@ declare namespace FourSlashInterface { getAndApplyCodeFix(errorCode?: number, index?: number): void; importFixAtPosition(expectedTextArray: string[], errorCode?: number, options?: UserPreferences): void; importFixModuleSpecifiers(marker: string, moduleSpecifiers: string[], options?: UserPreferences): void; - baselineAutoImports(marker: string, options?: UserPreferences): void; + baselineAutoImports(marker: string, fullNamesForCodeFix?: string[], options?: UserPreferences): void; navigationBar(json: any, options?: { checkSpans?: boolean }): void; navigationTree(json: any, options?: { checkSpans?: boolean }): void; From cde58e361d006060e496d07b8e3747490a4e6f1c Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 11 Jan 2023 11:00:00 -0800 Subject: [PATCH 10/15] Ensure ESM imports are type-only when possible --- src/harness/fourslashImpl.ts | 6 ++- src/harness/fourslashInterfaceImpl.ts | 6 +-- src/services/codefixes/importFixes.ts | 7 ++-- .../fourslash/autoImportVerbatimTypeOnly1.ts | 42 +++++++++++++++++++ tests/cases/fourslash/fourslash.ts | 2 +- 5 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/autoImportVerbatimTypeOnly1.ts diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 9a3084aa37184..9f7becff0fe11 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -2892,8 +2892,10 @@ export class TestState { this.applyChanges(fixes[index].changes); } - public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) { - this.goToMarker(markerName); + public applyCodeActionFromCompletion(markerName: string | undefined, options: FourSlashInterface.VerifyCompletionActionOptions) { + if (markerName !== undefined) { + this.goToMarker(markerName); + } const details = this.getCompletionEntryDetails(options.name, options.source, options.data, options.preferences); if (!details) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 15d42ad6b960f..59563f9e72f93 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -480,7 +480,7 @@ export class Verify extends VerifyNegatable { this.state.getAndApplyCodeActions(errorCode, index); } - public applyCodeActionFromCompletion(markerName: string, options: VerifyCompletionActionOptions): void { + public applyCodeActionFromCompletion(markerName: string | undefined, options: VerifyCompletionActionOptions): void { this.state.applyCodeActionFromCompletion(markerName, options); } @@ -492,8 +492,8 @@ export class Verify extends VerifyNegatable { this.state.verifyImportFixModuleSpecifiers(marker, moduleSpecifiers, preferences); } - public baselineAutoImports(marker: string, preferences?: ts.UserPreferences) { - this.state.baselineAutoImports(marker, preferences); + public baselineAutoImports(marker: string, fullNamesForCodeFix?: string[], options?: ts.UserPreferences) { + this.state.baselineAutoImports(marker, fullNamesForCodeFix, options); } public navigationBar(json: any, options?: { checkSpans?: boolean }) { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 598847867efb5..8d5c6a88d7b9f 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -666,7 +666,7 @@ function getAddAsTypeOnly( // Not writing a (top-level) type-only import here would create an error because the runtime dependency is unnecessary return AddAsTypeOnly.Required; } - if (compilerOptions.isolatedModules && compilerOptions.preserveValueImports && + if ((compilerOptions.isolatedModules && compilerOptions.preserveValueImports || compilerOptions.verbatimModuleSyntax) && (!(targetFlags & SymbolFlags.Value) || !!checker.getTypeOnlyAliasDeclaration(symbol)) ) { // A type-only import is required for this symbol if under these settings if the symbol will @@ -1262,7 +1262,7 @@ function getModuleSpecifierText(promotedDeclaration: ImportClause | ImportEquals function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaration: TypeOnlyAliasDeclaration, compilerOptions: CompilerOptions, sourceFile: SourceFile) { // See comment in `doAddExistingFix` on constant with the same name. - const convertExistingToTypeOnly = compilerOptions.preserveValueImports && compilerOptions.isolatedModules; + const convertExistingToTypeOnly = compilerOptions.preserveValueImports && compilerOptions.isolatedModules || compilerOptions.verbatimModuleSyntax; switch (aliasDeclaration.kind) { case SyntaxKind.ImportSpecifier: if (aliasDeclaration.isTypeOnly) { @@ -1347,7 +1347,8 @@ function doAddExistingFix( // never used in an emitting position). These are allowed to be imported without being type-only, // but the user has clearly already signified that they don't need them to be present at runtime // by placing them in a type-only import. So, just mark each specifier as type-only. - const convertExistingToTypeOnly = promoteFromTypeOnly && compilerOptions.preserveValueImports && compilerOptions.isolatedModules; + const convertExistingToTypeOnly = promoteFromTypeOnly + && (compilerOptions.preserveValueImports && compilerOptions.isolatedModules || compilerOptions.verbatimModuleSyntax); if (defaultImport) { Debug.assert(!clause.name, "Cannot add a default import to an import clause that already has one"); diff --git a/tests/cases/fourslash/autoImportVerbatimTypeOnly1.ts b/tests/cases/fourslash/autoImportVerbatimTypeOnly1.ts new file mode 100644 index 0000000000000..77e59525f47ce --- /dev/null +++ b/tests/cases/fourslash/autoImportVerbatimTypeOnly1.ts @@ -0,0 +1,42 @@ +/// + +// @module: nodenext +// @verbatimModuleSyntax: true + +// @Filename: /mod.ts +//// export const value = 0; +//// export class C { constructor(v: any) {} } +//// export interface I {} + +// @Filename: /a.mts +//// const x: /**/ + +verify.applyCodeActionFromCompletion("", { + name: "I", + source: "./mod", + description: `Add import from "./mod.js"`, + data: { + exportName: "I", + fileName: "/mod.ts", + moduleSpecifier: "./mod.js", + }, + newFileContent: `import type { I } from "./mod.js"; + +const x: `, +}); + +edit.insert("I = new C"); + +verify.applyCodeActionFromCompletion(/*markerName*/ undefined, { + name: "C", + source: "./mod", + description: `Update import from "./mod.js"`, + data: { + exportName: "C", + fileName: "/mod.ts", + moduleSpecifier: "./mod.js", + }, + newFileContent: `import { C, type I } from "./mod.js"; + +const x: I = new C`, +}); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index eee0eb4bf2b2d..7a8313454276a 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -285,7 +285,7 @@ declare namespace FourSlashInterface { assertHasRanges(ranges: Range[]): void; caretAtMarker(markerName?: string): void; completions(...options: CompletionsOptions[]): void; - applyCodeActionFromCompletion(markerName: string, options: { + applyCodeActionFromCompletion(markerName: string | undefined, options: { name: string, source?: string, data?: ts.CompletionEntryData, From 2e0acb2145b4ee2088015eb1b383bd3e25add758 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 11 Jan 2023 12:55:59 -0800 Subject: [PATCH 11/15] Update baselines after merge --- ...ModulesGlobalNamespacesAndEnums.errors.txt | 12 +++---- ...isolatedModulesGlobalNamespacesAndEnums.js | 2 +- .../getSupportedCodeFixes-can-be-proxied.js | 33 +++++++++++++++++-- .../fourslash/autoImportAllowTsExtensions2.ts | 2 +- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt index 9b11e24436e3a..2f1429e75bb3a 100644 --- a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.errors.txt @@ -1,12 +1,12 @@ -tests/cases/compiler/enum2.ts(3,9): error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. -tests/cases/compiler/enum2.ts(4,9): error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. -tests/cases/compiler/script-namespaces.ts(1,11): error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. +tests/cases/compiler/enum2.ts(3,9): error TS1279: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. +tests/cases/compiler/enum2.ts(4,9): error TS1279: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. +tests/cases/compiler/script-namespaces.ts(1,11): error TS1278: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. ==== tests/cases/compiler/script-namespaces.ts (1 errors) ==== namespace Instantiated { ~~~~~~~~~~~~ -!!! error TS1277: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. +!!! error TS1278: Namespaces are not allowed in global script files when 'isolatedModules' is enabled. If this file is not intended to be a global script, set 'moduleDetection' to 'force' or add an empty 'export {}' statement. export const x = 1; } namespace Uninstantiated { @@ -31,10 +31,10 @@ tests/cases/compiler/script-namespaces.ts(1,11): error TS1277: Namespaces are no D = d, E = A, // error ~ -!!! error TS1278: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. +!!! error TS1279: Cannot access 'A' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.A' instead. Y = X, // error ~ -!!! error TS1278: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. +!!! error TS1279: Cannot access 'X' from another file without qualification when 'isolatedModules' is enabled. Use 'Enum.X' instead. Z = Enum.A } diff --git a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js index bf2f2eb3ba238..02d64944f9b64 100644 --- a/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js +++ b/tests/baselines/reference/isolatedModulesGlobalNamespacesAndEnums.js @@ -40,7 +40,7 @@ var Instantiated; })(Instantiated || (Instantiated = {})); //// [module-namespaces.js] "use strict"; -exports.__esModule = true; +Object.defineProperty(exports, "__esModule", { value: true }); exports.Instantiated = void 0; var Instantiated; (function (Instantiated) { diff --git a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js index eaf791e9d05d7..20c3a85ac0704 100644 --- a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js +++ b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js @@ -562,7 +562,6 @@ Info 32 [00:01:13.000] response: "1203", "1206", "1207", - "1208", "1209", "1210", "1211", @@ -626,6 +625,12 @@ Info 32 [00:01:13.000] response: "1275", "1276", "1277", + "1278", + "1279", + "1280", + "1281", + "1282", + "1283", "1300", "1309", "1313", @@ -713,6 +718,8 @@ Info 32 [00:01:13.000] response: "1477", "1478", "1479", + "1484", + "1485", "2200", "2201", "2202", @@ -1306,6 +1313,8 @@ Info 32 [00:01:13.000] response: "5101", "5102", "5103", + "5104", + "5105", "6044", "6045", "6046", @@ -1896,7 +1905,6 @@ Info 38 [00:01:19.000] response: "1203", "1206", "1207", - "1208", "1209", "1210", "1211", @@ -1960,6 +1968,12 @@ Info 38 [00:01:19.000] response: "1275", "1276", "1277", + "1278", + "1279", + "1280", + "1281", + "1282", + "1283", "1300", "1309", "1313", @@ -2047,6 +2061,8 @@ Info 38 [00:01:19.000] response: "1477", "1478", "1479", + "1484", + "1485", "2200", "2201", "2202", @@ -2640,6 +2656,8 @@ Info 38 [00:01:19.000] response: "5101", "5102", "5103", + "5104", + "5105", "6044", "6045", "6046", @@ -3142,7 +3160,6 @@ Info 40 [00:01:21.000] response: "1203", "1206", "1207", - "1208", "1209", "1210", "1211", @@ -3206,6 +3223,12 @@ Info 40 [00:01:21.000] response: "1275", "1276", "1277", + "1278", + "1279", + "1280", + "1281", + "1282", + "1283", "1300", "1309", "1313", @@ -3293,6 +3316,8 @@ Info 40 [00:01:21.000] response: "1477", "1478", "1479", + "1484", + "1485", "2200", "2201", "2202", @@ -3886,6 +3911,8 @@ Info 40 [00:01:21.000] response: "5101", "5102", "5103", + "5104", + "5105", "6044", "6045", "6046", diff --git a/tests/cases/fourslash/autoImportAllowTsExtensions2.ts b/tests/cases/fourslash/autoImportAllowTsExtensions2.ts index 5fd8b0730bbf0..0757faed1f69f 100644 --- a/tests/cases/fourslash/autoImportAllowTsExtensions2.ts +++ b/tests/cases/fourslash/autoImportAllowTsExtensions2.ts @@ -19,4 +19,4 @@ // @Filename: /main.ts //// /**/ -verify.baselineAutoImports("", { importModuleSpecifierEnding: "js" }); +verify.baselineAutoImports("", /*fullNamesForCodeFix*/ undefined, { importModuleSpecifierEnding: "js" }); From 626820c0a9eebcb72dba96d67f9045cc2a132e78 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 11 Jan 2023 15:18:35 -0800 Subject: [PATCH 12/15] =?UTF-8?q?Disable=20marking=20stuff=20referenced=20?= =?UTF-8?q?since=20it=E2=80=99s=20not=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compiler/checker.ts | 28 +++++++++++++------ src/compiler/diagnosticMessages.json | 4 +++ ...oduleSyntaxInternalImportEquals.errors.txt | 20 +++++++++++++ ...erbatimModuleSyntaxInternalImportEquals.js | 22 +++++++++++++++ ...imModuleSyntaxInternalImportEquals.symbols | 25 +++++++++++++++++ ...atimModuleSyntaxInternalImportEquals.types | 27 ++++++++++++++++++ ...erbatimModuleSyntaxInternalImportEquals.ts | 13 +++++++++ 7 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.js create mode 100644 tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.symbols create mode 100644 tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.types create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4cded47854135..902ba5983410f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4440,6 +4440,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function markExportAsReferenced(node: ImportEqualsDeclaration | ExportSpecifier) { + if (compilerOptions.verbatimModuleSyntax) { + return; + } const symbol = getSymbolOfDeclaration(node); const target = resolveAlias(symbol); if (target) { @@ -4456,6 +4459,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // we reach a non-alias or an exported entity (which is always considered referenced). We do this by checking the target of // the alias as an expression (which recursively takes us back here if the target references another alias). function markAliasSymbolAsReferenced(symbol: Symbol) { + Debug.assert(!compilerOptions.verbatimModuleSyntax); const links = getSymbolLinks(symbol); if (!links.referenced) { links.referenced = true; @@ -27161,6 +27165,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function markAliasReferenced(symbol: Symbol, location: Node) { + if (compilerOptions.verbatimModuleSyntax) { + return; + } if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(location) && !getTypeOnlyAliasDeclaration(symbol, SymbolFlags.Value)) { const target = resolveAlias(symbol); if (getAllSymbolFlags(target) & (SymbolFlags.Value | SymbolFlags.ExportValue)) { @@ -30233,7 +30240,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { jsxFactorySym.isReferenced = SymbolFlags.All; // If react/jsxFactory symbol is alias, mark it as refereced - if (jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) { + if (!compilerOptions.verbatimModuleSyntax && jsxFactorySym.flags & SymbolFlags.Alias && !getTypeOnlyAliasDeclaration(jsxFactorySym)) { markAliasSymbolAsReferenced(jsxFactorySym); } } @@ -38634,7 +38641,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias; const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true); if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) { - if (symbolIsValue(rootSymbol) + if (!compilerOptions.verbatimModuleSyntax + && symbolIsValue(rootSymbol) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol)) && !getTypeOnlyAliasDeclaration(rootSymbol)) { markAliasSymbolAsReferenced(rootSymbol); @@ -42739,13 +42747,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportEqualsDeclaration: { if (compilerOptions.preserveValueImports || compilerOptions.verbatimModuleSyntax) { Debug.assertIsDefined(node.name, "An ImportClause with a symbol should have a name"); - const message = isType - ? compilerOptions.verbatimModuleSyntax - ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled - : Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled - : compilerOptions.verbatimModuleSyntax - ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled - : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; + const message = compilerOptions.verbatimModuleSyntax && isInternalModuleImportEqualsDeclaration(node) + ? Diagnostics.An_import_alias_cannot_resolve_to_a_type_or_type_only_declaration_when_verbatimModuleSyntax_is_enabled + : isType + ? compilerOptions.verbatimModuleSyntax + ? Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics._0_is_a_type_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled + : compilerOptions.verbatimModuleSyntax + ? Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_verbatimModuleSyntax_is_enabled + : Diagnostics._0_resolves_to_a_type_only_declaration_and_must_be_imported_using_a_type_only_import_when_preserveValueImports_and_isolatedModules_are_both_enabled; const name = idText(node.kind === SyntaxKind.ImportSpecifier ? node.propertyName || node.name : node.name); addTypeOnlyDeclarationRelatedInfo( error(node, message, name), diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index aa6e561eb02c1..da8f7e85c36b2 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -931,6 +931,10 @@ "category": "Error", "code": 1283 }, + "An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1284 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.errors.txt new file mode 100644 index 0000000000000..b8d19b2740d2a --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.errors.txt @@ -0,0 +1,20 @@ +tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts(2,13): error TS2503: Cannot find namespace 'NonExistent'. +tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts(10,1): error TS1284: An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled. + + +==== tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts (2 errors) ==== + export {}; + import f1 = NonExistent; + ~~~~~~~~~~~ +!!! error TS2503: Cannot find namespace 'NonExistent'. + + namespace Foo { + export const foo = 1; + export type T = any; + } + + import f2 = Foo.foo; + import f3 = Foo.T; + ~~~~~~~~~~~~~~~~~~ +!!! error TS1284: An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled. + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.js b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.js new file mode 100644 index 0000000000000..eff970067639b --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.js @@ -0,0 +1,22 @@ +//// [verbatimModuleSyntaxInternalImportEquals.ts] +export {}; +import f1 = NonExistent; + +namespace Foo { + export const foo = 1; + export type T = any; +} + +import f2 = Foo.foo; +import f3 = Foo.T; + + +//// [verbatimModuleSyntaxInternalImportEquals.js] +export {}; +var f1 = NonExistent; +var Foo; +(function (Foo) { + Foo.foo = 1; +})(Foo || (Foo = {})); +var f2 = Foo.foo; +var f3 = Foo.T; diff --git a/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.symbols b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.symbols new file mode 100644 index 0000000000000..06c8097ad65b6 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.symbols @@ -0,0 +1,25 @@ +=== tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts === +export {}; +import f1 = NonExistent; +>f1 : Symbol(f1, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 0, 10)) + +namespace Foo { +>Foo : Symbol(Foo, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 1, 24)) + + export const foo = 1; +>foo : Symbol(foo, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 4, 16)) + + export type T = any; +>T : Symbol(T, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 4, 25)) +} + +import f2 = Foo.foo; +>f2 : Symbol(f2, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 6, 1)) +>Foo : Symbol(Foo, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 1, 24)) +>foo : Symbol(f2, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 4, 16)) + +import f3 = Foo.T; +>f3 : Symbol(f3, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 8, 20)) +>Foo : Symbol(Foo, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 1, 24)) +>T : Symbol(f3, Decl(verbatimModuleSyntaxInternalImportEquals.ts, 4, 25)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.types b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.types new file mode 100644 index 0000000000000..5e34dac309147 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxInternalImportEquals.types @@ -0,0 +1,27 @@ +=== tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts === +export {}; +import f1 = NonExistent; +>f1 : any +>NonExistent : any + +namespace Foo { +>Foo : typeof Foo + + export const foo = 1; +>foo : 1 +>1 : 1 + + export type T = any; +>T : any +} + +import f2 = Foo.foo; +>f2 : 1 +>Foo : typeof Foo +>foo : 1 + +import f3 = Foo.T; +>f3 : any +>Foo : typeof Foo +>T : any + diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts new file mode 100644 index 0000000000000..a15b27cd2d34e --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxInternalImportEquals.ts @@ -0,0 +1,13 @@ +// @verbatimModuleSyntax: true +// @module: esnext + +export {}; +import f1 = NonExistent; + +namespace Foo { + export const foo = 1; + export type T = any; +} + +import f2 = Foo.foo; +import f3 = Foo.T; From f15d610a1b9b33fb08a065fc9c363f890019bfe8 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 11 Jan 2023 15:54:03 -0800 Subject: [PATCH 13/15] Deprecate importsNotUsedAsValues and preserveValueImports --- src/compiler/checker.ts | 22 ++++---- src/compiler/diagnosticMessages.json | 4 ++ src/compiler/program.ts | 54 ++++++++++++++++--- src/compiler/utilities.ts | 3 +- .../importsNotUsedAsValues_error.errors.txt | 4 ++ .../preserveUnusedImports.errors.txt | 18 +++++++ ...eImports(isolatedmodules=false).errors.txt | 4 ++ ...ueImports(isolatedmodules=true).errors.txt | 4 ++ ...s_errors(isolatedmodules=false).errors.txt | 50 +++++++++++++++++ ...ts_errors(isolatedmodules=true).errors.txt | 4 ++ ...eImports_importsNotUsedAsValues.errors.txt | 21 ++++++++ ...eserveValueImports_mixedImports.errors.txt | 4 ++ ...ValueImports_module(module=amd).errors.txt | 4 ++ ...Imports_module(module=commonjs).errors.txt | 4 ++ ...ueImports_module(module=es2015).errors.txt | 9 ++++ ...ueImports_module(module=system).errors.txt | 4 ++ ...tes-diagnostics-and-emit-for-decorators.js | 44 +++++++-------- ...mit-when-importsNotUsedAsValues-changes.js | 25 ++++----- .../getSupportedCodeFixes-can-be-proxied.js | 3 ++ .../verbatimModuleSyntaxCompat.errors.txt | 8 +++ 20 files changed, 235 insertions(+), 58 deletions(-) create mode 100644 tests/baselines/reference/preserveUnusedImports.errors.txt create mode 100644 tests/baselines/reference/preserveValueImports_errors(isolatedmodules=false).errors.txt create mode 100644 tests/baselines/reference/preserveValueImports_importsNotUsedAsValues.errors.txt create mode 100644 tests/baselines/reference/preserveValueImports_module(module=es2015).errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 902ba5983410f..b744ff626a1c1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2281,7 +2281,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator return; } - addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message)); // eslint-disable-line local/no-in-operator } function errorAndMaybeSuggestAwait( @@ -4832,7 +4832,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, chainDiagnosticMessages( + diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chainDiagnosticMessages( diagnosticDetails, Diagnostics.The_current_file_is_a_CommonJS_module_whose_imports_will_produce_require_calls_however_the_referenced_file_is_an_ECMAScript_module_and_cannot_be_imported_with_require_Consider_writing_a_dynamic_import_0_call_instead, moduleReference))); @@ -11595,7 +11595,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!isValidBaseType(reducedBaseType)) { const elaboration = elaborateNeverIntersection(/*errorInfo*/ undefined, baseType); const diagnostic = chainDiagnosticMessages(elaboration, Diagnostics.Base_constructor_return_type_0_is_not_an_object_type_or_intersection_of_object_types_with_statically_known_members, typeToString(reducedBaseType)); - diagnostics.add(createDiagnosticForNodeFromMessageChain(baseTypeNode.expression, diagnostic)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(baseTypeNode.expression), baseTypeNode.expression, diagnostic)); return type.resolvedBaseTypes = emptyArray; } if (type === reducedBaseType || hasBaseType(reducedBaseType, type)) { @@ -17013,7 +17013,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { errorInfo, Diagnostics.Element_implicitly_has_an_any_type_because_expression_of_type_0_can_t_be_used_to_index_type_1, typeToString(fullIndexType), typeToString(objectType) ); - diagnostics.add(createDiagnosticForNodeFromMessageChain(accessExpression, errorInfo)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(accessExpression), accessExpression, errorInfo)); } } } @@ -19857,7 +19857,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const diag = createDiagnosticForNodeFromMessageChain(errorNode!, errorInfo, relatedInformation); + const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode!), errorNode!, errorInfo, relatedInformation); if (relatedInfo) { addRelatedInfo(diag, ...relatedInfo); } @@ -31076,7 +31076,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } } - const resultDiagnostic = createDiagnosticForNodeFromMessageChain(propNode, errorInfo); + const resultDiagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(propNode), propNode, errorInfo); if (relatedInfo) { addRelatedInfo(resultDiagnostic, relatedInfo); } @@ -32505,7 +32505,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { diag = { file, start, length, code: chain.code, category: chain.category, messageText: chain, relatedInformation: related }; } else { - diag = createDiagnosticForNodeFromMessageChain(node, chain, related); + diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), node, chain, related); } addImplementationSuccessElaboration(candidatesForArgumentError[0], diag); diagnostics.add(diag); @@ -33137,7 +33137,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function invocationError(errorTarget: Node, apparentType: Type, kind: SignatureKind, relatedInformation?: DiagnosticRelatedInformation) { const { messageChain, relatedMessage: relatedInfo } = invocationErrorDetails(errorTarget, apparentType, kind); - const diagnostic = createDiagnosticForNodeFromMessageChain(errorTarget, messageChain); + const diagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorTarget), errorTarget, messageChain); if (relatedInfo) { addRelatedInfo(diagnostic, createDiagnosticForNode(errorTarget, relatedInfo)); } @@ -33248,7 +33248,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!callSignatures.length) { const errorDetails = invocationErrorDetails(node.expression, apparentType, SignatureKind.Call); const messageChain = chainDiagnosticMessages(errorDetails.messageChain, headMessage); - const diag = createDiagnosticForNodeFromMessageChain(node.expression, messageChain); + const diag = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node.expression), node.expression, messageChain); if (errorDetails.relatedMessage) { addRelatedInfo(diag, createDiagnosticForNode(node.expression, errorDetails.relatedMessage)); } @@ -38470,7 +38470,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { chain = chainDiagnosticMessages(chain, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForErrorOut.value)); } chain = chainDiagnosticMessages(chain, diagnosticMessage, arg0); - diagnostics.add(createDiagnosticForNodeFromMessageChain(errorNode, chain)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chain)); } return undefined; } @@ -42067,7 +42067,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let errorInfo = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Named_property_0_of_types_1_and_2_are_not_identical, symbolToString(prop), typeName1, typeName2); errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2, typeToString(type), typeName1, typeName2); - diagnostics.add(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(typeNode), typeNode, errorInfo)); } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index da8f7e85c36b2..60809f3b40e62 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4305,6 +4305,10 @@ "category": "Error", "code": 5105 }, + "Use '{0}' instead.": { + "category": "Message", + "code": 5106 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c6eb08ec375fb..7c2c20da6ebbf 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -34,6 +34,7 @@ import { createCompilerDiagnostic, createCompilerDiagnosticFromMessageChain, createDiagnosticCollection, + createDiagnosticForNodeFromMessageChain, createDiagnosticForNodeInSourceFile, createDiagnosticForRange, createFileDiagnostic, @@ -4310,15 +4311,35 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg if (options.out) { createDeprecatedDiagnosticForOption(version, "out"); } + if (options.importsNotUsedAsValues) { + createDeprecatedDiagnosticForOption(version, "importsNotUsedAsValues", /*value*/ undefined, "verbatimModuleSyntax"); + } + if (options.preserveValueImports) { + createDeprecatedDiagnosticForOption(version, "preserveValueImports", /*value*/ undefined, "verbatimModuleSyntax"); + } } - function createDeprecatedDiagnosticForOption(version: string, name: string, value?: string) { + function createDeprecatedDiagnosticForOption(version: string, name: string, value?: string, useInstead?: string) { if (version === DeprecationVersion.v6_0) { - createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name); + if (useInstead) { + const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead); + const chain = chainDiagnosticMessages(details, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name); + createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, chain); + } + else { + createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, Diagnostics.Flag_0_is_deprecated_Please_remove_it_from_your_configuration, value || name); + } } else { - createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, - 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); + if (useInstead) { + const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead); + 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); + createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, chain); + } + else { + createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, + 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); + } } } @@ -4567,13 +4588,21 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) { + function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessageChain): void; + function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): void; + function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): void { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax || !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2); if (needCompilerDiagnostic) { - programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2)); + // eslint-disable-next-line local/no-in-operator + if ("messageText" in message) { + programDiagnostics.add(createCompilerDiagnosticFromMessageChain(message)); + } + else { + programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2)); + } } } @@ -4593,10 +4622,19 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return _compilerOptionsObjectLiteralSyntax || undefined; } - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean { + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, messageChain: DiagnosticMessageChain): boolean; + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean; + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean; + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number): boolean { const props = getPropertyAssignment(objectLiteral, key1, key2); for (const prop of props) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2)); + // eslint-disable-next-line local/no-in-operator + if ("messageText" in message) { + programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message)); + } + else { + programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2)); + } } return !!props.length; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6043c9675b22b..d2c2ee6aeb04d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1715,8 +1715,7 @@ export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node } /** @internal */ -export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { - const sourceFile = getSourceFileOfNode(node); +export function createDiagnosticForNodeFromMessageChain(sourceFile: SourceFile, node: Node, messageChain: DiagnosticMessageChain, relatedInformation?: DiagnosticRelatedInformation[]): DiagnosticWithLocation { const span = getErrorSpanForNode(sourceFile, node); return createFileDiagnosticFromMessageChain(sourceFile, span.start, span.length, messageChain, relatedInformation); } diff --git a/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt b/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt index 7bc4014bc552c..b38928a9d3332 100644 --- a/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt +++ b/tests/baselines/reference/importsNotUsedAsValues_error.errors.txt @@ -1,3 +1,5 @@ +error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. /b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. /c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. /e.ts(1,1): error TS6192: All imports in import declaration are unused. @@ -5,6 +7,8 @@ /i.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== /a.ts (0 errors) ==== export default class {} export class A {} diff --git a/tests/baselines/reference/preserveUnusedImports.errors.txt b/tests/baselines/reference/preserveUnusedImports.errors.txt new file mode 100644 index 0000000000000..24fe33dd5118a --- /dev/null +++ b/tests/baselines/reference/preserveUnusedImports.errors.txt @@ -0,0 +1,18 @@ +error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + + +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +==== tests/cases/compiler/a.ts (0 errors) ==== + export type A = {}; + +==== tests/cases/compiler/b.ts (0 errors) ==== + export class B {} + +==== tests/cases/compiler/c.ts (0 errors) ==== + import { A } from './a'; + import { B } from './b'; + + let b: B; + \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports(isolatedmodules=false).errors.txt b/tests/baselines/reference/preserveValueImports(isolatedmodules=false).errors.txt index 681847a43c64a..be1be78a28af1 100644 --- a/tests/baselines/reference/preserveValueImports(isolatedmodules=false).errors.txt +++ b/tests/baselines/reference/preserveValueImports(isolatedmodules=false).errors.txt @@ -1,8 +1,12 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. tests/cases/conformance/externalModules/typeOnly/d.ts(1,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead. tests/cases/conformance/externalModules/typeOnly/e.ts(1,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== export default {}; export const b = 0; diff --git a/tests/baselines/reference/preserveValueImports(isolatedmodules=true).errors.txt b/tests/baselines/reference/preserveValueImports(isolatedmodules=true).errors.txt index aac66e08f6458..a0439704893ef 100644 --- a/tests/baselines/reference/preserveValueImports(isolatedmodules=true).errors.txt +++ b/tests/baselines/reference/preserveValueImports(isolatedmodules=true).errors.txt @@ -1,9 +1,13 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. tests/cases/conformance/externalModules/typeOnly/b.ts(1,19): error TS1444: 'D' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/d.ts(1,1): error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead. tests/cases/conformance/externalModules/typeOnly/e.ts(1,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. tests/cases/conformance/externalModules/typeOnly/e.ts(2,1): error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== export default {}; export const b = 0; diff --git a/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=false).errors.txt b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=false).errors.txt new file mode 100644 index 0000000000000..9dc097d8ffc6b --- /dev/null +++ b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=false).errors.txt @@ -0,0 +1,50 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + + +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== + export type A = {}; + export type { A as default }; + +==== tests/cases/conformance/externalModules/typeOnly/b.ts (0 errors) ==== + class B {}; + export type { B, B as default }; + +==== tests/cases/conformance/externalModules/typeOnly/c.ts (0 errors) ==== + import DefaultA from "./a"; + import { A } from "./a"; + import DefaultB from "./b"; + import { B } from "./b"; + +==== tests/cases/conformance/externalModules/typeOnly/c.fixed.ts (0 errors) ==== + import type DefaultA from "./a"; + import type { A } from "./a"; + import type DefaultB from "./b"; + import type { B } from "./b"; + +==== tests/cases/conformance/externalModules/typeOnly/d.ts (0 errors) ==== + export { A as AA } from "./a"; + export { B as BB } from "./b"; + +==== tests/cases/conformance/externalModules/typeOnly/d.fixed.ts (0 errors) ==== + export type { A as AA } from "./a"; + export type { B as BB } from "./b"; + +==== tests/cases/conformance/externalModules/typeOnly/e.ts (0 errors) ==== + import { AA, BB } from "./d"; + +==== tests/cases/conformance/externalModules/typeOnly/e.fixed.ts (0 errors) ==== + import type { AA, BB } from "./d"; + +==== tests/cases/conformance/externalModules/typeOnly/f.ts (0 errors) ==== + import type { A } from "./a"; + import type { B } from "./b"; + export { A, B as BB }; + +==== tests/cases/conformance/externalModules/typeOnly/f.fixed.ts (0 errors) ==== + import type { A } from "./a"; + import type { B } from "./b"; + export type { A, B as BB }; + \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt index 525ad99a2fc03..e93827ce25a8a 100644 --- a/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt +++ b/tests/baselines/reference/preserveValueImports_errors(isolatedmodules=true).errors.txt @@ -1,3 +1,5 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. tests/cases/conformance/externalModules/typeOnly/c.ts(1,8): error TS1444: 'DefaultA' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/c.ts(2,10): error TS1444: 'A' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. tests/cases/conformance/externalModules/typeOnly/c.ts(3,8): error TS1446: 'DefaultB' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. @@ -8,6 +10,8 @@ tests/cases/conformance/externalModules/typeOnly/e.ts(1,10): error TS1444: 'AA' tests/cases/conformance/externalModules/typeOnly/e.ts(1,14): error TS1446: 'BB' resolves to a type-only declaration and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/a.ts (0 errors) ==== export type A = {}; export type { A as default }; diff --git a/tests/baselines/reference/preserveValueImports_importsNotUsedAsValues.errors.txt b/tests/baselines/reference/preserveValueImports_importsNotUsedAsValues.errors.txt new file mode 100644 index 0000000000000..3f237a28462ac --- /dev/null +++ b/tests/baselines/reference/preserveValueImports_importsNotUsedAsValues.errors.txt @@ -0,0 +1,21 @@ +error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + + +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +==== /mod.ts (0 errors) ==== + export type A = unknown; + export type B = never; + export type C = any; + +==== /index.ts (0 errors) ==== + import { type A, type B, type C } from "./mod.js"; + +==== /reexport.ts (0 errors) ==== + export { type A, type B, type C } from "./mod.js"; + \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports_mixedImports.errors.txt b/tests/baselines/reference/preserveValueImports_mixedImports.errors.txt index 6ac4bec9faa83..91e78d21caaba 100644 --- a/tests/baselines/reference/preserveValueImports_mixedImports.errors.txt +++ b/tests/baselines/reference/preserveValueImports_mixedImports.errors.txt @@ -1,6 +1,10 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. /index.ts(1,21): error TS1444: 'ComponentProps' is a type and must be imported using a type-only import when 'preserveValueImports' and 'isolatedModules' are both enabled. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== /exports.ts (0 errors) ==== export function Component() {} export interface ComponentProps {} diff --git a/tests/baselines/reference/preserveValueImports_module(module=amd).errors.txt b/tests/baselines/reference/preserveValueImports_module(module=amd).errors.txt index 204342959ca1b..e51dd8b918161 100644 --- a/tests/baselines/reference/preserveValueImports_module(module=amd).errors.txt +++ b/tests/baselines/reference/preserveValueImports_module(module=amd).errors.txt @@ -1,7 +1,11 @@ error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. !!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/preserveValueImports_module.ts (0 errors) ==== export {}; \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports_module(module=commonjs).errors.txt b/tests/baselines/reference/preserveValueImports_module(module=commonjs).errors.txt index 204342959ca1b..e51dd8b918161 100644 --- a/tests/baselines/reference/preserveValueImports_module(module=commonjs).errors.txt +++ b/tests/baselines/reference/preserveValueImports_module(module=commonjs).errors.txt @@ -1,7 +1,11 @@ error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. !!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/preserveValueImports_module.ts (0 errors) ==== export {}; \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports_module(module=es2015).errors.txt b/tests/baselines/reference/preserveValueImports_module(module=es2015).errors.txt new file mode 100644 index 0000000000000..6eb172f0f6909 --- /dev/null +++ b/tests/baselines/reference/preserveValueImports_module(module=es2015).errors.txt @@ -0,0 +1,9 @@ +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + + +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +==== tests/cases/conformance/externalModules/typeOnly/preserveValueImports_module.ts (0 errors) ==== + export {}; + \ No newline at end of file diff --git a/tests/baselines/reference/preserveValueImports_module(module=system).errors.txt b/tests/baselines/reference/preserveValueImports_module(module=system).errors.txt index 204342959ca1b..e51dd8b918161 100644 --- a/tests/baselines/reference/preserveValueImports_module(module=system).errors.txt +++ b/tests/baselines/reference/preserveValueImports_module(module=system).errors.txt @@ -1,7 +1,11 @@ error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. !!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. ==== tests/cases/conformance/externalModules/typeOnly/preserveValueImports_module.ts (0 errors) ==== export {}; \ No newline at end of file diff --git a/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js b/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js index fb86001568eaa..d2b78aec53575 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js +++ b/tests/baselines/reference/tscWatch/programUpdates/updates-diagnostics-and-emit-for-decorators.js @@ -31,17 +31,13 @@ Output:: >> Screen clear [12:00:15 AM] Starting compilation in watch mode... -a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +tsconfig.json:1:36 - error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. -1 import {B} from './b' -  ~~~~~~~~~~~~~~~~~~~~~ +1 {"compilerOptions":{"target":"es6","importsNotUsedAsValues":"error"}} +   ~~~~~~~~~~~~~~~~~~~~~~~~ -a.ts:3:14 - error TS1219: Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option in your 'tsconfig' or 'jsconfig' to remove this warning. - -3 export class A { -   ~ - -[12:00:20 AM] Found 2 errors. Watching for file changes. +[12:00:20 AM] Found 1 error. Watching for file changes. @@ -53,10 +49,7 @@ Program files:: /a.ts /a/lib/lib.d.ts -Semantic diagnostics in builder refreshed for:: -/b.ts -/a.ts -/a/lib/lib.d.ts +No cached semantic diagnostics in the builder:: Shape signatures in builder refreshed for:: /b.ts (used version) @@ -115,10 +108,11 @@ Output:: >> Screen clear [12:00:23 AM] File change detected. Starting incremental compilation... -a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +tsconfig.json:1:36 - error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. -1 import {B} from './b' -  ~~~~~~~~~~~~~~~~~~~~~ +1 {"compilerOptions":{"target":"es6","importsNotUsedAsValues":"error","experimentalDecorators":true}} +   ~~~~~~~~~~~~~~~~~~~~~~~~ [12:00:24 AM] Found 1 error. Watching for file changes. @@ -132,10 +126,7 @@ Program files:: /a.ts /a/lib/lib.d.ts -Semantic diagnostics in builder refreshed for:: -/b.ts -/a.ts -/a/lib/lib.d.ts +No cached semantic diagnostics in the builder:: No shapes updated in the builder:: @@ -169,7 +160,13 @@ Output:: >> Screen clear [12:00:27 AM] File change detected. Starting incremental compilation... -[12:00:34 AM] Found 0 errors. Watching for file changes. +tsconfig.json:1:36 - error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + +1 {"compilerOptions":{"target":"es6","importsNotUsedAsValues":"error","experimentalDecorators":true,"emitDecoratorMetadata":true}} +   ~~~~~~~~~~~~~~~~~~~~~~~~ + +[12:00:34 AM] Found 1 error. Watching for file changes. @@ -181,10 +178,7 @@ Program files:: /a.ts /a/lib/lib.d.ts -Semantic diagnostics in builder refreshed for:: -/b.ts -/a.ts -/a/lib/lib.d.ts +No cached semantic diagnostics in the builder:: No shapes updated in the builder:: diff --git a/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js b/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js index b09c716cd13f7..ac38736a4aaef 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js +++ b/tests/baselines/reference/tscWatch/programUpdates/updates-errors-and-emit-when-importsNotUsedAsValues-changes.js @@ -155,10 +155,11 @@ Output:: >> Screen clear [12:00:43 AM] File change detected. Starting incremental compilation... -b.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'. +tsconfig.json:1:21 - error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. -1 import {C} from './a'; -  ~~~~~~~~~~~~~~~~~~~~~~ +1 {"compilerOptions":{"importsNotUsedAsValues":"error"}} +   ~~~~~~~~~~~~~~~~~~~~~~~~ [12:00:50 AM] Found 1 error. Watching for file changes. @@ -172,10 +173,7 @@ Program files:: /user/username/projects/myproject/a.ts /user/username/projects/myproject/b.ts -Semantic diagnostics in builder refreshed for:: -/a/lib/lib.d.ts -/user/username/projects/myproject/a.ts -/user/username/projects/myproject/b.ts +No cached semantic diagnostics in the builder:: No shapes updated in the builder:: @@ -221,7 +219,13 @@ Output:: >> Screen clear [12:00:54 AM] File change detected. Starting incremental compilation... -[12:01:01 AM] Found 0 errors. Watching for file changes. +tsconfig.json:1:21 - error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + +1 {"compilerOptions":{"importsNotUsedAsValues":"preserve"}} +   ~~~~~~~~~~~~~~~~~~~~~~~~ + +[12:01:01 AM] Found 1 error. Watching for file changes. @@ -233,10 +237,7 @@ Program files:: /user/username/projects/myproject/a.ts /user/username/projects/myproject/b.ts -Semantic diagnostics in builder refreshed for:: -/a/lib/lib.d.ts -/user/username/projects/myproject/a.ts -/user/username/projects/myproject/b.ts +No cached semantic diagnostics in the builder:: No shapes updated in the builder:: diff --git a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js index 20c3a85ac0704..897a8f26041c8 100644 --- a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js +++ b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js @@ -631,6 +631,7 @@ Info 32 [00:01:13.000] response: "1281", "1282", "1283", + "1284", "1300", "1309", "1313", @@ -1974,6 +1975,7 @@ Info 38 [00:01:19.000] response: "1281", "1282", "1283", + "1284", "1300", "1309", "1313", @@ -3229,6 +3231,7 @@ Info 40 [00:01:21.000] response: "1281", "1282", "1283", + "1284", "1300", "1309", "1313", diff --git a/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt index 1806bae46e07c..6473ca791e504 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt +++ b/tests/baselines/reference/verbatimModuleSyntaxCompat.errors.txt @@ -1,4 +1,8 @@ error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. @@ -6,6 +10,10 @@ error TS5105: Option 'verbatimModuleSyntax' cannot be used when 'module' is set !!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. !!! error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. !!! error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. !!! error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. From addcca8b3434d5084120317ee984457e8dd3d7ba Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 11 Jan 2023 17:00:46 -0800 Subject: [PATCH 14/15] Clean up redundancy errors --- src/compiler/program.ts | 26 ++++++++++-- .../verbatimModuleSyntaxCompat2.errors.txt | 35 ++++++++++++++++ .../verbatimModuleSyntaxCompat3.errors.txt | 29 +++++++++++++ .../verbatimModuleSyntaxCompat4.errors.txt | 41 +++++++++++++++++++ .../verbatimModuleSyntaxCompat2.ts | 13 ++++++ .../verbatimModuleSyntaxCompat3.ts | 19 +++++++++ .../verbatimModuleSyntaxCompat4.ts | 19 +++++++++ 7 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/verbatimModuleSyntaxCompat2.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxCompat3.errors.txt create mode 100644 tests/baselines/reference/verbatimModuleSyntaxCompat4.errors.txt create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat2.ts create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat3.ts create mode 100644 tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat4.ts diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 7c2c20da6ebbf..381a029b74c2f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -4211,13 +4211,13 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg createDiagnosticForOptionName(Diagnostics.Option_verbatimModuleSyntax_cannot_be_used_when_module_is_set_to_UMD_AMD_or_System, "verbatimModuleSyntax"); } if (options.isolatedModules) { - createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "isolatedModules", "verbatimModuleSyntax"); + createRedundantOptionDiagnostic("isolatedModules", "verbatimModuleSyntax"); } if (options.preserveValueImports) { - createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "preserveValueImports", "verbatimModuleSyntax"); + createRedundantOptionDiagnostic("preserveValueImports", "verbatimModuleSyntax"); } if (options.importsNotUsedAsValues) { - createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, "importsNotUsedAsValues", "verbatimModuleSyntax"); + createRedundantOptionDiagnostic("importsNotUsedAsValues", "verbatimModuleSyntax"); } } @@ -4639,6 +4639,26 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return !!props.length; } + /** + * Only creates a diagnostic on the option key specified by `errorOnOption`. + * If both options are specified in the program in separate config files via `extends`, + * a diagnostic is only created if `errorOnOption` is specified in the leaf config file. + * Useful if `redundantWithOption` represents a superset of the functionality of `errorOnOption`: + * if a user inherits `errorOnOption` from a base config file, it's still valid and useful to + * override it in the leaf config file. + */ + function createRedundantOptionDiagnostic(errorOnOption: string, redundantWithOption: string) { + const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); + if (compilerOptionsObjectLiteralSyntax) { + // This is a no-op if `errorOnOption` isn't present in the leaf config file. + createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, /*onKey*/ true, errorOnOption, /*key2*/ undefined, Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption); + } + else { + // There was no config file, so both options were specified on the command line. + createDiagnosticForOptionName(Diagnostics.Option_0_is_redundant_and_cannot_be_specified_with_option_1, errorOnOption, redundantWithOption); + } + } + function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) { hasEmitBlockingDiagnostics.set(toPath(emitFileName), true); programDiagnostics.add(diag); diff --git a/tests/baselines/reference/verbatimModuleSyntaxCompat2.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxCompat2.errors.txt new file mode 100644 index 0000000000000..8e2a3c5f4c5fe --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxCompat2.errors.txt @@ -0,0 +1,35 @@ +/tsconfig.json(4,9): error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +/tsconfig.json(5,9): error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +/tsconfig.json(5,9): error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +/tsconfig.json(5,9): error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +/tsconfig.json(6,9): error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +/tsconfig.json(6,9): error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + + +==== /tsconfig.json (6 errors) ==== + { + "compilerOptions": { + "verbatimModuleSyntax": true, + "isolatedModules": true, + ~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + "preserveValueImports": true, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + "importsNotUsedAsValues": "error", + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + } + } +==== /index.ts (0 errors) ==== + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxCompat3.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxCompat3.errors.txt new file mode 100644 index 0000000000000..5aa5b84e69a9e --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxCompat3.errors.txt @@ -0,0 +1,29 @@ +error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. + + +!!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. +==== /tsconfig.json (0 errors) ==== + { + "extends": "./tsconfig.base.json", + "compilerOptions": { + "verbatimModuleSyntax": true + } + } +==== /tsconfig.base.json (0 errors) ==== + { + "compilerOptions": { + "isolatedModules": true, + "preserveValueImports": true, + "importsNotUsedAsValues": "error", + } + } +==== /index.ts (0 errors) ==== + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxCompat4.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxCompat4.errors.txt new file mode 100644 index 0000000000000..ab8abdb445c96 --- /dev/null +++ b/tests/baselines/reference/verbatimModuleSyntaxCompat4.errors.txt @@ -0,0 +1,41 @@ +/tsconfig.json(4,9): error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +/tsconfig.json(5,9): error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. +/tsconfig.json(5,9): error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +/tsconfig.json(5,9): error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. +/tsconfig.json(6,9): error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. + Use 'verbatimModuleSyntax' instead. +/tsconfig.json(6,9): error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + + +==== /tsconfig.json (6 errors) ==== + { + "extends": "./tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + ~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'isolatedModules' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + "preserveValueImports": true, + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5095: Option 'preserveValueImports' can only be used when 'module' is set to 'es2015' or later. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5101: Flag 'preserveValueImports' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'preserveValueImports' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + "importsNotUsedAsValues": "error", + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5101: Flag 'importsNotUsedAsValues' is deprecated and will stop functioning in TypeScript 5.5. Specify 'ignoreDeprecations: "5.0"' to silence this error. +!!! error TS5101: Use 'verbatimModuleSyntax' instead. + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS5104: Option 'importsNotUsedAsValues' is redundant and cannot be specified with option 'verbatimModuleSyntax'. + } + } +==== /tsconfig.base.json (0 errors) ==== + { + "compilerOptions": { + "verbatimModuleSyntax": true + } + } +==== /index.ts (0 errors) ==== + \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat2.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat2.ts new file mode 100644 index 0000000000000..341920fe6bb75 --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat2.ts @@ -0,0 +1,13 @@ +// @noTypesAndSymbols: true +// @noEmit: true + +// @Filename: /tsconfig.json +{ + "compilerOptions": { + "verbatimModuleSyntax": true, + "isolatedModules": true, + "preserveValueImports": true, + "importsNotUsedAsValues": "error", + } +} +// @Filename: /index.ts \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat3.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat3.ts new file mode 100644 index 0000000000000..4139d3bf047fa --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat3.ts @@ -0,0 +1,19 @@ +// @noTypesAndSymbols: true +// @noEmit: true + +// @Filename: /tsconfig.base.json +{ + "compilerOptions": { + "isolatedModules": true, + "preserveValueImports": true, + "importsNotUsedAsValues": "error", + } +} +// @Filename: /tsconfig.json +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "verbatimModuleSyntax": true + } +} +// @Filename: /index.ts \ No newline at end of file diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat4.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat4.ts new file mode 100644 index 0000000000000..e9cc196c08458 --- /dev/null +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxCompat4.ts @@ -0,0 +1,19 @@ +// @noTypesAndSymbols: true +// @noEmit: true + +// @Filename: /tsconfig.base.json +{ + "compilerOptions": { + "verbatimModuleSyntax": true + } +} +// @Filename: /tsconfig.json +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "isolatedModules": true, + "preserveValueImports": true, + "importsNotUsedAsValues": "error", + } +} +// @Filename: /index.ts \ No newline at end of file From b72c5d07c24ab2d94ae22372d950f3e399cee30a Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 19 Jan 2023 15:42:01 -0800 Subject: [PATCH 15/15] Allow export modifier on uninstantiated namespaces in CJS, fix export default restrictions --- src/compiler/checker.ts | 34 ++++++++-- src/compiler/diagnosticMessages.json | 14 +++- ...erbatimModuleSyntaxNoElisionESM.errors.txt | 20 ++++++ .../verbatimModuleSyntaxNoElisionESM.js | 27 ++++++++ .../verbatimModuleSyntaxNoElisionESM.symbols | 22 +++++++ .../verbatimModuleSyntaxNoElisionESM.types | 20 ++++++ ...atimModuleSyntaxRestrictionsCJS.errors.txt | 66 +++++++++++++++---- .../verbatimModuleSyntaxRestrictionsCJS.js | 48 +++++++++++++- ...erbatimModuleSyntaxRestrictionsCJS.symbols | 37 +++++++++++ .../verbatimModuleSyntaxRestrictionsCJS.types | 33 ++++++++++ .../verbatimModuleSyntaxNoElisionESM.ts | 14 ++++ .../verbatimModuleSyntaxRestrictionsCJS.ts | 23 ++++++- 12 files changed, 334 insertions(+), 24 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b744ff626a1c1..b84438862c086 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42535,6 +42535,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass; } } + if (compilerOptions.verbatimModuleSyntax && node.parent.kind === SyntaxKind.SourceFile) { + const exportModifier = node.modifiers?.find(m => m.kind === SyntaxKind.ExportKeyword); + if (exportModifier) { + error(exportModifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + } + } } if (isAmbientExternalModule) { @@ -43134,6 +43140,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkTypeAssignableTo(checkExpressionCached(node.expression), getTypeFromTypeNode(typeAnnotationNode), node.expression); } + const isIllegalExportDefaultInCJS = !node.isExportEquals && + compilerOptions.verbatimModuleSyntax && + (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS); + if (node.expression.kind === SyntaxKind.Identifier) { const id = node.expression as Identifier; const sym = resolveEntityName(id, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, node); @@ -43143,12 +43153,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (getAllSymbolFlags(sym) & SymbolFlags.Value) { // However if it is a value, we need to check it's being used correctly checkExpressionCached(id); - if (compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) { - error(id, Diagnostics.An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, idText(id)); + if (!isIllegalExportDefaultInCJS && compilerOptions.verbatimModuleSyntax && getTypeOnlyAliasDeclaration(sym, SymbolFlags.Value)) { + error(id, + node.isExportEquals + ? Diagnostics.An_export_declaration_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration + : Diagnostics.An_export_default_must_reference_a_real_value_when_verbatimModuleSyntax_is_enabled_but_0_resolves_to_a_type_only_declaration, + idText(id)); } } - else if (compilerOptions.verbatimModuleSyntax) { - error(id, Diagnostics.An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, idText(id)); + else if (!isIllegalExportDefaultInCJS && compilerOptions.verbatimModuleSyntax) { + error(id, + node.isExportEquals + ? Diagnostics.An_export_declaration_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type + : Diagnostics.An_export_default_must_reference_a_value_when_verbatimModuleSyntax_is_enabled_but_0_only_refers_to_a_type, + idText(id)); } } else { @@ -43163,6 +43181,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { checkExpressionCached(node.expression); } + if (isIllegalExportDefaultInCJS) { + error(node, Diagnostics.ESM_syntax_is_not_allowed_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + } + checkExternalModuleExports(container); if ((node.flags & NodeFlags.Ambient) && !isEntityNameExpression(node.expression)) { @@ -45784,10 +45806,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { !(node.flags & NodeFlags.Ambient) && node.kind !== SyntaxKind.TypeAliasDeclaration && node.kind !== SyntaxKind.InterfaceDeclaration && + // ModuleDeclaration needs to be checked that it is uninstantiated later + node.kind !== SyntaxKind.ModuleDeclaration && node.parent.kind === SyntaxKind.SourceFile && (moduleKind === ModuleKind.CommonJS || getSourceFileOfNode(node).impliedNodeFormat === ModuleKind.CommonJS) ) { - return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_can_only_be_used_on_type_aliases_and_interfaces_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); + return grammarErrorOnNode(modifier, Diagnostics.A_top_level_export_modifier_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled); } if (flags & ModifierFlags.Export) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 60809f3b40e62..45dc77733dfd3 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -923,18 +923,26 @@ "category": "Error", "code": 1281 }, - "ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { + "An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": { "category": "Error", "code": 1282 }, - "A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { + "An 'export default' must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": { "category": "Error", "code": 1283 }, - "An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled.": { + "ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { "category": "Error", "code": 1284 }, + "A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1285 + }, + "An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled.": { + "category": "Error", + "code": 1286 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt index feee2583483f8..c745f64237147 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.errors.txt @@ -2,6 +2,8 @@ /b.ts(5,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. /b.ts(6,10): error TS1205: Re-exporting a type when 'verbatimModuleSyntax' is enabled requires using 'export type'. /c.ts(1,10): error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. +/main6.ts(2,16): error TS1282: An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. +/main7.ts(2,16): error TS1283: An 'export default' must reference a real value when 'verbatimModuleSyntax' is enabled, but 'C' resolves to a type-only declaration. ==== /a.ts (0 errors) ==== @@ -31,4 +33,22 @@ ~~~~~~ !!! error TS1485: 'AClass' resolves to a type-only declaration and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. !!! related TS1377 /b.ts:9:15: 'AClass' was exported here. + +==== /main4.ts (0 errors) ==== + export default 1; // ok + +==== /main5.ts (0 errors) ==== + export default class C {} // ok + +==== /main6.ts (1 errors) ==== + interface I {} + export default I; // error + ~ +!!! error TS1282: An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but 'I' only refers to a type. + +==== /main7.ts (1 errors) ==== + import type C from "./main5"; + export default C; // error + ~ +!!! error TS1283: An 'export default' must reference a real value when 'verbatimModuleSyntax' is enabled, but 'C' resolves to a type-only declaration. \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js index 38b5791c09db6..f38feb4540da2 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.js @@ -19,6 +19,20 @@ export type { AClass } from "./a"; //// [c.ts] import { AClass } from "./b"; +//// [main4.ts] +export default 1; // ok + +//// [main5.ts] +export default class C {} // ok + +//// [main6.ts] +interface I {} +export default I; // error + +//// [main7.ts] +import type C from "./main5"; +export default C; // error + //// [a.js] export var a = 0; @@ -36,3 +50,16 @@ export { A as A2 } from "./a"; export {} from "./a"; //// [c.js] import { AClass } from "./b"; +//// [main4.js] +export default 1; // ok +//// [main5.js] +var C = /** @class */ (function () { + function C() { + } + return C; +}()); // ok +export default C; +//// [main6.js] +export default I; // error +//// [main7.js] +export default C; // error diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols index 8b84501fbed25..51c729c2f3197 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.symbols @@ -47,3 +47,25 @@ export type { AClass } from "./a"; import { AClass } from "./b"; >AClass : Symbol(AClass, Decl(c.ts, 0, 8)) +=== /main4.ts === + +export default 1; // ok + +=== /main5.ts === +export default class C {} // ok +>C : Symbol(C, Decl(main5.ts, 0, 0)) + +=== /main6.ts === +interface I {} +>I : Symbol(I, Decl(main6.ts, 0, 0)) + +export default I; // error +>I : Symbol(I, Decl(main6.ts, 0, 0)) + +=== /main7.ts === +import type C from "./main5"; +>C : Symbol(C, Decl(main7.ts, 0, 6)) + +export default C; // error +>C : Symbol(C, Decl(main7.ts, 0, 6)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types index 5bea23a96f2a2..65593d71ce47d 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types +++ b/tests/baselines/reference/verbatimModuleSyntaxNoElisionESM.types @@ -48,3 +48,23 @@ export type { AClass } from "./a"; import { AClass } from "./b"; >AClass : typeof AClass +=== /main4.ts === + +export default 1; // ok + +=== /main5.ts === +export default class C {} // ok +>C : C + +=== /main6.ts === +interface I {} +export default I; // error +>I : I + +=== /main7.ts === +import type C from "./main5"; +>C : C + +export default C; // error +>C : C + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt index abc057262e689..71c7f1144bc5b 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.errors.txt @@ -1,37 +1,54 @@ -/main.ts(1,8): error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. -/main.ts(2,13): error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. -/main.ts(3,10): error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. -/main.ts(5,1): error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. -/main.ts(8,1): error TS1283: A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/decl.d.ts(2,1): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(1,8): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(2,13): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(3,10): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(5,1): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(8,1): error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main.ts(14,1): error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. /main2.ts(2,1): error TS2309: An export assignment cannot be used in a module with other exported elements. +/main4.ts(1,1): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main5.ts(1,1): error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main6.ts(2,1): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +/main7.ts(2,1): error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. -==== /decl.d.ts (0 errors) ==== +==== /decl.d.ts (1 errors) ==== declare function esmy(): void; export default esmy; + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. export declare function funciton(): void; -==== /main.ts (5 errors) ==== +==== /main.ts (6 errors) ==== import esmy from "./decl"; // error ~~~~ -!!! error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. import * as esmy2 from "./decl"; // error ~~~~~ -!!! error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. import { funciton } from "./decl"; // error ~~~~~~~~ -!!! error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. import type { funciton as funciton2 } from "./decl"; // ok I guess? import("./decl"); // error ~~~~~~~~~~~~~~~~ -!!! error TS1282: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. type T = typeof import("./decl"); // ok export {}; // error export const x = 1; // error ~~~~~~ -!!! error TS1283: A top-level 'export' modifier can only be used on type aliases and interfaces in a CommonJS module when 'verbatimModuleSyntax' is enabled. +!!! error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. export interface I {} // ok export type { T }; // ok + export namespace JustTypes { + export type T = number; + } + export namespace Values { // error + ~~~~~~ +!!! error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. + export const x = 1; + } + export default interface Default {} // sketchy, but ok ==== /main2.ts (1 errors) ==== export interface I {} @@ -44,4 +61,27 @@ export const x = 1; export interface I {} } - export = ns; \ No newline at end of file + export = ns; + +==== /main4.ts (1 errors) ==== + export default 1; // error + ~~~~~~~~~~~~~~~~~ +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + +==== /main5.ts (1 errors) ==== + export default class C {} // error + ~~~~~~ +!!! error TS1285: A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled. + +==== /main6.ts (1 errors) ==== + interface I {} + export default I; // error + ~~~~~~~~~~~~~~~~~ +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + +==== /main7.ts (1 errors) ==== + import type esmy from "./decl"; + export default esmy; // error + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS1284: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled. + \ No newline at end of file diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js index 34e20f57b2364..e48c08b8b4c28 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.js @@ -16,6 +16,13 @@ export {}; // error export const x = 1; // error export interface I {} // ok export type { T }; // ok +export namespace JustTypes { + export type T = number; +} +export namespace Values { // error + export const x = 1; +} +export default interface Default {} // sketchy, but ok //// [main2.ts] export interface I {} @@ -26,7 +33,22 @@ namespace ns { export const x = 1; export interface I {} } -export = ns; +export = ns; + +//// [main4.ts] +export default 1; // error + +//// [main5.ts] +export default class C {} // error + +//// [main6.ts] +interface I {} +export default I; // error + +//// [main7.ts] +import type esmy from "./decl"; +export default esmy; // error + //// [main.js] "use strict"; @@ -57,12 +79,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.x = void 0; +exports.Values = exports.x = void 0; const decl_1 = __importDefault(require("./decl")); // error const esmy2 = __importStar(require("./decl")); // error const decl_2 = require("./decl"); // error Promise.resolve().then(() => __importStar(require("./decl"))); // error exports.x = 1; // error +var Values; +(function (Values) { + Values.x = 1; +})(Values = exports.Values || (exports.Values = {})); //// [main2.js] "use strict"; module.exports = { x: 1 }; @@ -73,3 +99,21 @@ var ns; ns.x = 1; })(ns || (ns = {})); module.exports = ns; +//// [main4.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = 1; // error +//// [main5.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class C { +} // error +exports.default = C; +//// [main6.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = I; // error +//// [main7.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = esmy; // error diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols index a68231ac91e78..e85557f10c91b 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.symbols @@ -38,6 +38,21 @@ export interface I {} // ok export type { T }; // ok >T : Symbol(T, Decl(main.ts, 9, 13)) +export namespace JustTypes { +>JustTypes : Symbol(JustTypes, Decl(main.ts, 9, 18)) + + export type T = number; +>T : Symbol(T, Decl(main.ts, 10, 28)) +} +export namespace Values { // error +>Values : Symbol(Values, Decl(main.ts, 12, 1)) + + export const x = 1; +>x : Symbol(x, Decl(main.ts, 14, 16)) +} +export default interface Default {} // sketchy, but ok +>Default : Symbol(Default, Decl(main.ts, 15, 1)) + === /main2.ts === export interface I {} >I : Symbol(I, Decl(main2.ts, 0, 0)) @@ -58,3 +73,25 @@ namespace ns { export = ns; >ns : Symbol(ns, Decl(main3.ts, 0, 0)) +=== /main4.ts === + +export default 1; // error + +=== /main5.ts === +export default class C {} // error +>C : Symbol(C, Decl(main5.ts, 0, 0)) + +=== /main6.ts === +interface I {} +>I : Symbol(I, Decl(main6.ts, 0, 0)) + +export default I; // error +>I : Symbol(I, Decl(main6.ts, 0, 0)) + +=== /main7.ts === +import type esmy from "./decl"; +>esmy : Symbol(esmy, Decl(main7.ts, 0, 6)) + +export default esmy; // error +>esmy : Symbol(esmy, Decl(main7.ts, 0, 6)) + diff --git a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types index 0d4cb520bf80e..968c15c3f93b6 100644 --- a/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types +++ b/tests/baselines/reference/verbatimModuleSyntaxRestrictionsCJS.types @@ -38,6 +38,19 @@ export interface I {} // ok export type { T }; // ok >T : typeof import("/decl") +export namespace JustTypes { + export type T = number; +>T : number +} +export namespace Values { // error +>Values : typeof Values + + export const x = 1; +>x : 1 +>1 : 1 +} +export default interface Default {} // sketchy, but ok + === /main2.ts === export interface I {} export = { x: 1 }; @@ -58,3 +71,23 @@ namespace ns { export = ns; >ns : typeof ns +=== /main4.ts === + +export default 1; // error + +=== /main5.ts === +export default class C {} // error +>C : C + +=== /main6.ts === +interface I {} +export default I; // error +>I : I + +=== /main7.ts === +import type esmy from "./decl"; +>esmy : any + +export default esmy; // error +>esmy : () => void + diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts index 074ae5cbffd81..71a3ee277bb12 100644 --- a/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxNoElisionESM.ts @@ -20,3 +20,17 @@ export type { AClass } from "./a"; // @Filename: /c.ts import { AClass } from "./b"; + +// @Filename: /main4.ts +export default 1; // ok + +// @Filename: /main5.ts +export default class C {} // ok + +// @Filename: /main6.ts +interface I {} +export default I; // error + +// @Filename: /main7.ts +import type C from "./main5"; +export default C; // error diff --git a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts index fa7202b56a775..d1df5e8bbd5a2 100644 --- a/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts +++ b/tests/cases/conformance/externalModules/verbatimModuleSyntaxRestrictionsCJS.ts @@ -20,6 +20,13 @@ export {}; // error export const x = 1; // error export interface I {} // ok export type { T }; // ok +export namespace JustTypes { + export type T = number; +} +export namespace Values { // error + export const x = 1; +} +export default interface Default {} // sketchy, but ok // @Filename: /main2.ts export interface I {} @@ -30,4 +37,18 @@ namespace ns { export const x = 1; export interface I {} } -export = ns; \ No newline at end of file +export = ns; + +// @Filename: /main4.ts +export default 1; // error + +// @Filename: /main5.ts +export default class C {} // error + +// @Filename: /main6.ts +interface I {} +export default I; // error + +// @Filename: /main7.ts +import type esmy from "./decl"; +export default esmy; // error