mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Add verbatimModuleSyntax, deprecate importsNotUsedAsValues and preserveValueImports (#52203)
This commit is contained in:
+140
-59
@@ -7,6 +7,7 @@ import {
|
||||
addRange,
|
||||
addRelatedInfo,
|
||||
addSyntheticLeadingComment,
|
||||
AliasDeclarationNode,
|
||||
AllAccessorDeclarations,
|
||||
AmbientModuleDeclaration,
|
||||
and,
|
||||
@@ -283,6 +284,7 @@ import {
|
||||
getInitializerOfBinaryExpression,
|
||||
getInterfaceBaseTypeNodes,
|
||||
getInvokedExpression,
|
||||
getIsolatedModules,
|
||||
getJSDocClassTag,
|
||||
getJSDocDeprecatedTag,
|
||||
getJSDocEnumTag,
|
||||
@@ -441,6 +443,7 @@ import {
|
||||
isBindableStaticElementAccessExpression,
|
||||
isBindableStaticNameExpression,
|
||||
isBindingElement,
|
||||
isBindingElementOfBareOrAccessedRequire,
|
||||
isBindingPattern,
|
||||
isBlock,
|
||||
isBlockOrCatchScoped,
|
||||
@@ -1451,6 +1454,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;
|
||||
@@ -2310,7 +2314,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(
|
||||
@@ -3091,6 +3095,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
if (result = lookup(getSymbolOfDeclaration(location as EnumDeclaration)?.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;
|
||||
@@ -4474,6 +4486,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) {
|
||||
@@ -4490,6 +4505,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;
|
||||
@@ -4862,7 +4878,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)));
|
||||
@@ -11651,7 +11667,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)) {
|
||||
@@ -17110,7 +17126,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19954,7 +19970,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);
|
||||
}
|
||||
@@ -27279,13 +27295,16 @@ 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)) {
|
||||
// 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))
|
||||
) {
|
||||
@@ -30366,7 +30385,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);
|
||||
}
|
||||
}
|
||||
@@ -30937,7 +30956,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)
|
||||
)) {
|
||||
@@ -31202,7 +31221,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
const resultDiagnostic = createDiagnosticForNodeFromMessageChain(propNode, errorInfo);
|
||||
const resultDiagnostic = createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(propNode), propNode, errorInfo);
|
||||
if (relatedInfo) {
|
||||
addRelatedInfo(resultDiagnostic, relatedInfo);
|
||||
}
|
||||
@@ -32337,7 +32356,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if ("message" in message) { // eslint-disable-line local/no-in-operator
|
||||
return createDiagnosticForNode(node, message, arg0, arg1, arg2, arg3);
|
||||
}
|
||||
return createDiagnosticForNodeFromMessageChain(node, message);
|
||||
return createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), node, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32667,7 +32686,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);
|
||||
@@ -33296,7 +33315,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));
|
||||
}
|
||||
@@ -33407,7 +33426,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));
|
||||
}
|
||||
@@ -37151,11 +37170,11 @@ 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39031,7 +39050,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;
|
||||
}
|
||||
@@ -39243,13 +39262,14 @@ 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);
|
||||
}
|
||||
else if (forDecoratorMetadata
|
||||
&& compilerOptions.isolatedModules
|
||||
&& getIsolatedModules(compilerOptions)
|
||||
&& getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015
|
||||
&& !symbolIsValue(rootSymbol)
|
||||
&& !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration)) {
|
||||
@@ -40354,8 +40374,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
// For a commonjs `const x = require`, validate the alias and exit
|
||||
const symbol = getSymbolOfDeclaration(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;
|
||||
}
|
||||
|
||||
@@ -42761,7 +42781,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43202,25 +43222,38 @@ 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);
|
||||
&& 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);
|
||||
}
|
||||
}
|
||||
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 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 (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43362,7 +43395,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 = getSymbolOfDeclaration(node);
|
||||
const target = resolveAlias(symbol);
|
||||
|
||||
@@ -43422,7 +43455,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);
|
||||
@@ -43432,11 +43465,17 @@ 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
|
||||
? 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;
|
||||
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),
|
||||
@@ -43445,7 +43484,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;
|
||||
}
|
||||
@@ -43453,21 +43492,25 @@ 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
|
||||
);
|
||||
return;
|
||||
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);
|
||||
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)) {
|
||||
@@ -43811,30 +43854,51 @@ 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);
|
||||
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 (!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 (!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 {
|
||||
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 {
|
||||
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)) {
|
||||
@@ -45423,6 +45487,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function isValueAliasDeclaration(node: Node): boolean {
|
||||
Debug.assert(!compilerOptions.verbatimModuleSyntax);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return isAliasResolvedToValue(getSymbolOfDeclaration(node as ImportEqualsDeclaration));
|
||||
@@ -45476,6 +45541,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean {
|
||||
Debug.assert(!compilerOptions.verbatimModuleSyntax);
|
||||
if (isAliasSymbolDeclaration(node)) {
|
||||
const symbol = getSymbolOfDeclaration(node as Declaration);
|
||||
const links = symbol && getSymbolLinks(symbol);
|
||||
@@ -46461,6 +46527,17 @@ 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 &&
|
||||
// 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_cannot_be_used_on_value_declarations_in_a_CommonJS_module_when_verbatimModuleSyntax_is_enabled);
|
||||
}
|
||||
if (flags & ModifierFlags.Export) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "export");
|
||||
}
|
||||
@@ -47983,6 +48060,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);
|
||||
}
|
||||
|
||||
@@ -789,6 +789,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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -871,7 +867,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
|
||||
},
|
||||
@@ -915,6 +911,42 @@
|
||||
"category": "Error",
|
||||
"code": 1279
|
||||
},
|
||||
"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": 1280
|
||||
},
|
||||
"Cannot access '{0}' from another file without qualification when '{1}' is enabled. Use '{2}' instead.": {
|
||||
"category": "Error",
|
||||
"code": 1281
|
||||
},
|
||||
"An 'export =' declaration must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": {
|
||||
"category": "Error",
|
||||
"code": 1282
|
||||
},
|
||||
"An 'export =' declaration must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": {
|
||||
"category": "Error",
|
||||
"code": 1283
|
||||
},
|
||||
"An 'export default' must reference a value when 'verbatimModuleSyntax' is enabled, but '{0}' only refers to a type.": {
|
||||
"category": "Error",
|
||||
"code": 1284
|
||||
},
|
||||
"An 'export default' must reference a real value when 'verbatimModuleSyntax' is enabled, but '{0}' resolves to a type-only declaration.": {
|
||||
"category": "Error",
|
||||
"code": 1285
|
||||
},
|
||||
"ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.": {
|
||||
"category": "Error",
|
||||
"code": 1286
|
||||
},
|
||||
"A top-level 'export' modifier cannot be used on value declarations in a CommonJS module when 'verbatimModuleSyntax' is enabled.": {
|
||||
"category": "Error",
|
||||
"code": 1287
|
||||
},
|
||||
"An import alias cannot resolve to a type or type-only declaration when 'verbatimModuleSyntax' is enabled.": {
|
||||
"category": "Error",
|
||||
"code": 1288
|
||||
},
|
||||
|
||||
"'with' statements are not allowed in an async function block.": {
|
||||
"category": "Error",
|
||||
@@ -1444,7 +1476,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
|
||||
},
|
||||
@@ -1557,6 +1589,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",
|
||||
@@ -3223,7 +3263,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
|
||||
},
|
||||
@@ -4217,7 +4257,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
|
||||
},
|
||||
@@ -4269,6 +4309,18 @@
|
||||
"category": "Error",
|
||||
"code": 5103
|
||||
},
|
||||
"Option '{0}' is redundant and cannot be specified with option '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 5104
|
||||
},
|
||||
"Option 'verbatimModuleSyntax' cannot be used when 'module' is set to 'UMD', 'AMD', or 'System'.": {
|
||||
"category": "Error",
|
||||
"code": 5105
|
||||
},
|
||||
"Use '{0}' instead.": {
|
||||
"category": "Message",
|
||||
"code": 5106
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
@@ -6003,6 +6055,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",
|
||||
|
||||
+86
-20
@@ -35,6 +35,7 @@ import {
|
||||
createCompilerDiagnostic,
|
||||
createCompilerDiagnosticFromMessageChain,
|
||||
createDiagnosticCollection,
|
||||
createDiagnosticForNodeFromMessageChain,
|
||||
createDiagnosticForNodeInSourceFile,
|
||||
createDiagnosticForRange,
|
||||
createFileDiagnostic,
|
||||
@@ -4117,21 +4118,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) {
|
||||
@@ -4240,7 +4233,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) {
|
||||
createRedundantOptionDiagnostic("isolatedModules", "verbatimModuleSyntax");
|
||||
}
|
||||
if (options.preserveValueImports) {
|
||||
createRedundantOptionDiagnostic("preserveValueImports", "verbatimModuleSyntax");
|
||||
}
|
||||
if (options.importsNotUsedAsValues) {
|
||||
createRedundantOptionDiagnostic("importsNotUsedAsValues", "verbatimModuleSyntax");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly)) {
|
||||
@@ -4333,15 +4342,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4590,13 +4619,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4616,14 +4653,43 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
@@ -2264,7 +2264,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);
|
||||
@@ -2289,7 +2289,7 @@ export function transformTypeScript(context: TransformationContext) {
|
||||
*/
|
||||
function visitExportAssignment(node: ExportAssignment): VisitResult<Statement | undefined> {
|
||||
// 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;
|
||||
}
|
||||
@@ -2312,7 +2312,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(
|
||||
@@ -2358,7 +2358,7 @@ export function transformTypeScript(context: TransformationContext) {
|
||||
*/
|
||||
function visitExportSpecifier(node: ExportSpecifier): VisitResult<ExportSpecifier> | undefined {
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2714,7 +2714,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));
|
||||
|
||||
@@ -5453,6 +5453,21 @@ export type AnyImportOrRequire = AnyImportSyntax | VariableDeclarationInitialize
|
||||
/** @internal */
|
||||
export type AnyImportOrBareOrAccessedRequire = AnyImportSyntax | VariableDeclarationInitializedTo<RequireOrImportCall | AccessExpression>;
|
||||
|
||||
/** @internal */
|
||||
export type AliasDeclarationNode =
|
||||
| ImportEqualsDeclaration
|
||||
| VariableDeclarationInitializedTo<RequireOrImportCall
|
||||
| AccessExpression>
|
||||
| ImportClause
|
||||
| NamespaceImport
|
||||
| ImportSpecifier
|
||||
| ExportSpecifier
|
||||
| NamespaceExport
|
||||
| BindingElementOfBareOrAccessedRequire;
|
||||
|
||||
/** @internal */
|
||||
export type BindingElementOfBareOrAccessedRequire = BindingElement & { parent: { parent: VariableDeclarationInitializedTo<RequireOrImportCall | AccessExpression> } };
|
||||
|
||||
/** @internal */
|
||||
export type AnyImportOrRequireStatement = AnyImportSyntax | RequireVariableStatement;
|
||||
|
||||
@@ -7087,6 +7102,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;
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
addRange,
|
||||
affectsDeclarationPathOptionDeclarations,
|
||||
affectsEmitOptionDeclarations,
|
||||
AliasDeclarationNode,
|
||||
AllAccessorDeclarations,
|
||||
AmbientModuleDeclaration,
|
||||
AmpersandAmpersandEqualsToken,
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
BindableStaticElementAccessExpression,
|
||||
BindableStaticNameExpression,
|
||||
BindingElement,
|
||||
BindingElementOfBareOrAccessedRequire,
|
||||
Block,
|
||||
BundleFileSection,
|
||||
BundleFileSectionKind,
|
||||
@@ -197,8 +199,8 @@ import {
|
||||
HasExpressionInitializer,
|
||||
hasExtension,
|
||||
HasFlowNode,
|
||||
HasInitializer,
|
||||
hasInitializer,
|
||||
HasInitializer,
|
||||
HasJSDoc,
|
||||
hasJSDocNodes,
|
||||
HasModifiers,
|
||||
@@ -234,6 +236,7 @@ import {
|
||||
isArrowFunction,
|
||||
isBigIntLiteral,
|
||||
isBinaryExpression,
|
||||
isBindingElement,
|
||||
isBindingPattern,
|
||||
isCallExpression,
|
||||
isClassDeclaration,
|
||||
@@ -1731,8 +1734,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);
|
||||
}
|
||||
@@ -3116,6 +3118,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 &&
|
||||
@@ -3542,14 +3549,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);
|
||||
}
|
||||
@@ -8009,6 +8025,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;
|
||||
|
||||
@@ -2985,8 +2985,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) {
|
||||
@@ -3213,9 +3215,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")}`);
|
||||
@@ -3301,7 +3303,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 = {
|
||||
@@ -3312,10 +3314,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)!;
|
||||
|
||||
@@ -3339,7 +3343,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);
|
||||
}
|
||||
|
||||
@@ -4791,3 +4824,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
@@ -685,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
|
||||
@@ -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 {
|
||||
@@ -1018,6 +1029,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;
|
||||
@@ -1072,7 +1087,7 @@ function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, h
|
||||
const exportInfo = getExportInfos(symbolName, isJSXTagName(symbolToken), getMeaningFromLocation(symbolToken), cancellationToken, sourceFile, program, useAutoImportProvider, host, preferences);
|
||||
return arrayFrom(
|
||||
flatMapIterator(exportInfo.values(), 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),
|
||||
fix => ({ fix, symbolName, errorIdentifierText: symbolToken.text, isJsxNamespaceFix: symbolName !== symbolToken.text })
|
||||
);
|
||||
});
|
||||
@@ -1142,7 +1157,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);
|
||||
}
|
||||
|
||||
@@ -1216,12 +1231,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, preferences);
|
||||
if (qualification) {
|
||||
addNamespaceQualifier(changes, sourceFile, qualification);
|
||||
}
|
||||
return includeSymbolNameInDescription
|
||||
? [Diagnostics.Import_0_from_1, symbolName, moduleSpecifier]
|
||||
: [Diagnostics.Add_import_from_0, moduleSpecifier];
|
||||
@@ -1246,7 +1266,7 @@ function getModuleSpecifierText(promotedDeclaration: ImportClause | ImportEquals
|
||||
|
||||
function promoteFromTypeOnly(changes: textChanges.ChangeTracker, aliasDeclaration: TypeOnlyAliasDeclaration, compilerOptions: CompilerOptions, sourceFile: SourceFile, preferences: UserPreferences) {
|
||||
// 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) {
|
||||
@@ -1332,7 +1352,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");
|
||||
@@ -1421,11 +1442,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));
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ import {
|
||||
getLineAndCharacterOfPosition,
|
||||
getLineStartPositionForPosition,
|
||||
getLocalSymbolForExportDefault,
|
||||
getNameForExportedSymbol,
|
||||
getNameOfDeclaration,
|
||||
getNameTable,
|
||||
getNewLineCharacter,
|
||||
@@ -558,7 +557,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;
|
||||
@@ -606,9 +605,9 @@ function resolvingModuleSpecifiers<TReturn>(
|
||||
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++;
|
||||
}
|
||||
@@ -617,7 +616,7 @@ function resolvingModuleSpecifiers<TReturn>(
|
||||
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) {
|
||||
@@ -779,7 +778,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}'`);
|
||||
@@ -2525,7 +2524,7 @@ function getCompletionEntryCodeActionsAndSourceDisplay(
|
||||
targetSymbol,
|
||||
moduleSymbol,
|
||||
sourceFile,
|
||||
getNameForExportedSymbol(symbol, getEmitScriptTarget(compilerOptions), isJsxOpeningTagName),
|
||||
name,
|
||||
isJsxOpeningTagName,
|
||||
host,
|
||||
program,
|
||||
@@ -3196,7 +3195,7 @@ function getCompletionData(
|
||||
moduleSymbol,
|
||||
symbol: firstAccessibleSymbol,
|
||||
targetFlags: skipAlias(firstAccessibleSymbol, typeChecker).flags,
|
||||
}], firstAccessibleSymbol.name, position, isValidTypeOnlyAliasUseSite(location)) || {};
|
||||
}], position, isValidTypeOnlyAliasUseSite(location)) || {};
|
||||
|
||||
if (moduleSpecifier) {
|
||||
const origin: SymbolOriginInfoResolvedExport = {
|
||||
@@ -3518,7 +3517,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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user