mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Simplify handling of node:-prefixed modules in auto-imports (#59702)
This commit is contained in:
@@ -11,8 +11,8 @@ import {
|
||||
InstallPackageAction,
|
||||
isExternalModuleNameRelative,
|
||||
isStringLiteral,
|
||||
JsTyping,
|
||||
LanguageServiceHost,
|
||||
nodeCoreModules,
|
||||
parsePackageName,
|
||||
SourceFile,
|
||||
tryCast,
|
||||
@@ -71,6 +71,6 @@ function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string
|
||||
|
||||
function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined {
|
||||
return diagCode === errorCodeCannotFindModule
|
||||
? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
|
||||
? (nodeCoreModules.has(packageName) ? "@types/node" : undefined)
|
||||
: (host.isKnownTypesPackageName?.(packageName) ? getTypesPackageName(packageName) : undefined);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
ExportKind,
|
||||
ExportMapInfoKey,
|
||||
factory,
|
||||
fileContainsPackageImport,
|
||||
findAncestor,
|
||||
first,
|
||||
firstDefined,
|
||||
@@ -84,7 +83,7 @@ import {
|
||||
isExternalModuleReference,
|
||||
isFullSourceFile,
|
||||
isIdentifier,
|
||||
isImportableFile,
|
||||
isImportable,
|
||||
isImportDeclaration,
|
||||
isImportEqualsDeclaration,
|
||||
isIntrinsicJsxName,
|
||||
@@ -1542,10 +1541,7 @@ function getExportInfos(
|
||||
});
|
||||
function addSymbol(moduleSymbol: Symbol, toFile: SourceFile | undefined, exportedSymbol: Symbol, exportKind: ExportKind, program: Program, isFromPackageJson: boolean): void {
|
||||
const moduleSpecifierResolutionHost = getModuleSpecifierResolutionHost(isFromPackageJson);
|
||||
if (
|
||||
toFile && isImportableFile(program, fromFile, toFile, preferences, packageJsonFilter, moduleSpecifierResolutionHost, moduleSpecifierCache) ||
|
||||
(!toFile && packageJsonFilter.allowsImportingAmbientModule(moduleSymbol, moduleSpecifierResolutionHost) || fileContainsPackageImport(fromFile, stripQuotes(moduleSymbol.name)))
|
||||
) {
|
||||
if (isImportable(program, fromFile, toFile, moduleSymbol, preferences, packageJsonFilter, moduleSpecifierResolutionHost, moduleSpecifierCache)) {
|
||||
const checker = program.getTypeChecker();
|
||||
originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { symbol: exportedSymbol, moduleSymbol, moduleFileName: toFile?.fileName, exportKind, targetFlags: skipAlias(exportedSymbol, checker).flags, isFromPackageJson });
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ import {
|
||||
Expression,
|
||||
ExpressionWithTypeArguments,
|
||||
factory,
|
||||
fileContainsPackageImport,
|
||||
filter,
|
||||
find,
|
||||
findAncestor,
|
||||
@@ -175,7 +174,7 @@ import {
|
||||
isIdentifierPart,
|
||||
isIdentifierStart,
|
||||
isIdentifierText,
|
||||
isImportableFile,
|
||||
isImportable,
|
||||
isImportAttributes,
|
||||
isImportDeclaration,
|
||||
isImportEqualsDeclaration,
|
||||
@@ -274,7 +273,6 @@ import {
|
||||
JSDocTypedefTag,
|
||||
JSDocTypeExpression,
|
||||
JSDocTypeTag,
|
||||
JsTyping,
|
||||
JsxAttribute,
|
||||
JsxAttributes,
|
||||
JsxClosingElement,
|
||||
@@ -344,7 +342,6 @@ import {
|
||||
SemanticMeaning,
|
||||
setEmitFlags,
|
||||
setSnippetElement,
|
||||
shouldUseUriStyleNodeCoreModules,
|
||||
SignatureHelp,
|
||||
SignatureKind,
|
||||
singleElementArray,
|
||||
@@ -4221,19 +4218,11 @@ function getCompletionData(
|
||||
);
|
||||
|
||||
function isImportableExportInfo(info: SymbolExportInfo) {
|
||||
const moduleFile = tryCast(info.moduleSymbol.valueDeclaration, isSourceFile);
|
||||
if (!moduleFile) {
|
||||
const moduleName = stripQuotes(info.moduleSymbol.name);
|
||||
if (JsTyping.nodeCoreModules.has(moduleName) && startsWith(moduleName, "node:") !== shouldUseUriStyleNodeCoreModules(sourceFile, program)) {
|
||||
return false;
|
||||
}
|
||||
return (packageJsonFilter?.allowsImportingAmbientModule(info.moduleSymbol, getModuleSpecifierResolutionHost(info.isFromPackageJson)) ?? true)
|
||||
|| fileContainsPackageImport(sourceFile, moduleName);
|
||||
}
|
||||
return isImportableFile(
|
||||
return isImportable(
|
||||
info.isFromPackageJson ? packageJsonAutoImportProvider! : program,
|
||||
sourceFile,
|
||||
moduleFile,
|
||||
tryCast(info.moduleSymbol.valueDeclaration, isSourceFile),
|
||||
info.moduleSymbol,
|
||||
preferences,
|
||||
packageJsonFilter,
|
||||
getModuleSpecifierResolutionHost(info.isFromPackageJson),
|
||||
@@ -4371,7 +4360,7 @@ function getCompletionData(
|
||||
// dprint-ignore
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.CommaToken:
|
||||
switch (containingNodeKind) {
|
||||
switch (containingNodeKind) {
|
||||
case SyntaxKind.CallExpression: // func( a, |
|
||||
case SyntaxKind.NewExpression: { // new C(a, |
|
||||
const expression = (contextToken.parent as CallExpression | NewExpression).expression;
|
||||
@@ -4454,7 +4443,7 @@ function getCompletionData(
|
||||
}
|
||||
|
||||
case SyntaxKind.TemplateHead:
|
||||
return {
|
||||
return {
|
||||
defaultCommitCharacters: allCommitCharacters,
|
||||
isNewIdentifierLocation: containingNodeKind === SyntaxKind.TemplateExpression // `aa ${|
|
||||
};
|
||||
|
||||
@@ -38,12 +38,14 @@ import {
|
||||
ModuleSpecifierResolutionHost,
|
||||
moduleSpecifiers,
|
||||
moduleSymbolToValidIdentifier,
|
||||
nodeCoreModules,
|
||||
nodeModulesPathPart,
|
||||
PackageJsonImportFilter,
|
||||
Path,
|
||||
pathContainsNodeModules,
|
||||
Program,
|
||||
ScriptTarget,
|
||||
shouldUseUriStyleNodeCoreModules,
|
||||
skipAlias,
|
||||
SourceFile,
|
||||
startsWith,
|
||||
@@ -362,48 +364,61 @@ export function createCacheableExportInfoMap(host: CacheableExportInfoMapHost):
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isImportableFile(
|
||||
export function isImportable(
|
||||
program: Program,
|
||||
from: SourceFile,
|
||||
to: SourceFile,
|
||||
fromFile: SourceFile,
|
||||
toFile: SourceFile | undefined,
|
||||
toModule: Symbol,
|
||||
preferences: UserPreferences,
|
||||
packageJsonFilter: PackageJsonImportFilter | undefined,
|
||||
moduleSpecifierResolutionHost: ModuleSpecifierResolutionHost,
|
||||
moduleSpecifierCache: ModuleSpecifierCache | undefined,
|
||||
): boolean {
|
||||
if (from === to) return false;
|
||||
const cachedResult = moduleSpecifierCache?.get(from.path, to.path, preferences, {});
|
||||
if (!toFile) {
|
||||
// Ambient module
|
||||
let useNodePrefix;
|
||||
const moduleName = stripQuotes(toModule.name);
|
||||
if (nodeCoreModules.has(moduleName) && (useNodePrefix = shouldUseUriStyleNodeCoreModules(fromFile, program)) !== undefined) {
|
||||
return useNodePrefix === startsWith(moduleName, "node:");
|
||||
}
|
||||
return !packageJsonFilter
|
||||
|| packageJsonFilter.allowsImportingAmbientModule(toModule, moduleSpecifierResolutionHost)
|
||||
|| fileContainsPackageImport(fromFile, moduleName);
|
||||
}
|
||||
|
||||
Debug.assertIsDefined(toFile);
|
||||
if (fromFile === toFile) return false;
|
||||
const cachedResult = moduleSpecifierCache?.get(fromFile.path, toFile.path, preferences, {});
|
||||
if (cachedResult?.isBlockedByPackageJsonDependencies !== undefined) {
|
||||
return !cachedResult.isBlockedByPackageJsonDependencies || !!cachedResult.packageName && fileContainsPackageImport(from, cachedResult.packageName);
|
||||
return !cachedResult.isBlockedByPackageJsonDependencies || !!cachedResult.packageName && fileContainsPackageImport(fromFile, cachedResult.packageName);
|
||||
}
|
||||
|
||||
const getCanonicalFileName = hostGetCanonicalFileName(moduleSpecifierResolutionHost);
|
||||
const globalTypingsCache = moduleSpecifierResolutionHost.getGlobalTypingsCacheLocation?.();
|
||||
const hasImportablePath = !!moduleSpecifiers.forEachFileNameOfModule(
|
||||
from.fileName,
|
||||
to.fileName,
|
||||
fromFile.fileName,
|
||||
toFile.fileName,
|
||||
moduleSpecifierResolutionHost,
|
||||
/*preferSymlinks*/ false,
|
||||
toPath => {
|
||||
const toFile = program.getSourceFile(toPath);
|
||||
const file = program.getSourceFile(toPath);
|
||||
// Determine to import using toPath only if toPath is what we were looking at
|
||||
// or there doesnt exist the file in the program by the symlink
|
||||
return (toFile === to || !toFile) &&
|
||||
isImportablePath(from.fileName, toPath, getCanonicalFileName, globalTypingsCache);
|
||||
return (file === toFile || !file) &&
|
||||
isImportablePath(fromFile.fileName, toPath, getCanonicalFileName, globalTypingsCache);
|
||||
},
|
||||
);
|
||||
|
||||
if (packageJsonFilter) {
|
||||
const importInfo = hasImportablePath ? packageJsonFilter.getSourceFileInfo(to, moduleSpecifierResolutionHost) : undefined;
|
||||
moduleSpecifierCache?.setBlockedByPackageJsonDependencies(from.path, to.path, preferences, {}, importInfo?.packageName, !importInfo?.importable);
|
||||
return !!importInfo?.importable || !!importInfo?.packageName && fileContainsPackageImport(from, importInfo.packageName);
|
||||
const importInfo = hasImportablePath ? packageJsonFilter.getSourceFileInfo(toFile, moduleSpecifierResolutionHost) : undefined;
|
||||
moduleSpecifierCache?.setBlockedByPackageJsonDependencies(fromFile.path, toFile.path, preferences, {}, importInfo?.packageName, !importInfo?.importable);
|
||||
return !!importInfo?.importable || hasImportablePath && !!importInfo?.packageName && fileContainsPackageImport(fromFile, importInfo.packageName);
|
||||
}
|
||||
|
||||
return hasImportablePath;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function fileContainsPackageImport(sourceFile: SourceFile, packageName: string) {
|
||||
function fileContainsPackageImport(sourceFile: SourceFile, packageName: string) {
|
||||
return sourceFile.imports && sourceFile.imports.some(i => i.text === packageName || i.text.startsWith(packageName + "/"));
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ import {
|
||||
equateStringsCaseInsensitive,
|
||||
equateStringsCaseSensitive,
|
||||
escapeString,
|
||||
exclusivelyPrefixedNodeCoreModules,
|
||||
ExportAssignment,
|
||||
ExportDeclaration,
|
||||
Expression,
|
||||
@@ -271,7 +272,6 @@ import {
|
||||
JSDocLinkDisplayPart,
|
||||
JSDocLinkPlain,
|
||||
JSDocTypedefTag,
|
||||
JsTyping,
|
||||
JsxEmit,
|
||||
JsxOpeningLikeElement,
|
||||
JsxTagNameExpression,
|
||||
@@ -297,6 +297,7 @@ import {
|
||||
Node,
|
||||
NodeArray,
|
||||
NodeBuilderFlags,
|
||||
nodeCoreModules,
|
||||
NodeFlags,
|
||||
nodeIsMissing,
|
||||
nodeIsPresent,
|
||||
@@ -3851,7 +3852,7 @@ export function createPackageJsonImportFilter(fromFile: SourceFile | FutureSourc
|
||||
// from Node core modules or not. We can start by seeing if the user is actually using
|
||||
// any node core modules, as opposed to simply having @types/node accidentally as a
|
||||
// dependency of a dependency.
|
||||
if (isFullSourceFile(fromFile) && isSourceFileJS(fromFile) && JsTyping.nodeCoreModules.has(moduleSpecifier)) {
|
||||
if (isFullSourceFile(fromFile) && isSourceFileJS(fromFile) && nodeCoreModules.has(moduleSpecifier)) {
|
||||
if (usesNodeCoreModules === undefined) {
|
||||
usesNodeCoreModules = consumesNodeCoreModules(fromFile);
|
||||
}
|
||||
@@ -3896,7 +3897,7 @@ export function createPackageJsonImportFilter(fromFile: SourceFile | FutureSourc
|
||||
|
||||
/** @internal */
|
||||
export function consumesNodeCoreModules(sourceFile: SourceFile): boolean {
|
||||
return some(sourceFile.imports, ({ text }) => JsTyping.nodeCoreModules.has(text));
|
||||
return some(sourceFile.imports, ({ text }) => nodeCoreModules.has(text));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -4123,12 +4124,18 @@ export function isDeprecatedDeclaration(decl: Declaration) {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function shouldUseUriStyleNodeCoreModules(file: SourceFile | FutureSourceFile, program: Program): boolean {
|
||||
const decisionFromFile = firstDefined(file.imports, node => {
|
||||
if (JsTyping.nodeCoreModules.has(node.text)) {
|
||||
return startsWith(node.text, "node:");
|
||||
export function shouldUseUriStyleNodeCoreModules(file: SourceFile | FutureSourceFile, program: Program): boolean | undefined {
|
||||
let decisionFromFile;
|
||||
for (const node of file.imports) {
|
||||
if (nodeCoreModules.has(node.text) && !exclusivelyPrefixedNodeCoreModules.has(node.text)) {
|
||||
if (startsWith(node.text, "node:")) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
decisionFromFile = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return decisionFromFile ?? program.usesUriStyleNodeCoreModules;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user