Simplify handling of `node:`-prefixed modules in auto-imports (#59702)

This commit is contained in:
Andrew Branch 2024-08-21 16:43:21 -07:00 коммит произвёл GitHub
Родитель f6ec916313
Коммит a5eec2485f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
16 изменённых файлов: 943 добавлений и 191 удалений

Просмотреть файл

@ -75,6 +75,7 @@ import {
ensureTrailingDirectorySeparator,
equateStringsCaseInsensitive,
equateStringsCaseSensitive,
exclusivelyPrefixedNodeCoreModules,
explainIfFileIsRedirectAndImpliedFormat,
ExportAssignment,
ExportDeclaration,
@ -323,6 +324,7 @@ import {
TypeChecker,
typeDirectiveIsEqualTo,
TypeReferenceDirectiveResolutionCache,
unprefixedNodeCoreModules,
VariableDeclaration,
VariableStatement,
Version,
@ -1758,7 +1760,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
let sourceFileToPackageName = new Map<Path, string>();
// Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it.
let redirectTargetsMap = createMultiMap<Path, string>();
let usesUriStyleNodeCoreModules = false;
let usesUriStyleNodeCoreModules: boolean | undefined;
/**
* map with
@ -3499,7 +3501,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
setParentRecursive(node, /*incremental*/ false); // we need parent data on imports before the program is fully bound, so we ensure it's set here
imports = append(imports, moduleNameExpr);
if (!usesUriStyleNodeCoreModules && currentNodeModulesDepth === 0 && !file.isDeclarationFile) {
usesUriStyleNodeCoreModules = startsWith(moduleNameExpr.text, "node:");
if (startsWith(moduleNameExpr.text, "node:") && !exclusivelyPrefixedNodeCoreModules.has(moduleNameExpr.text)) {
// Presence of `node:` prefix takes precedence over unprefixed node core modules
usesUriStyleNodeCoreModules = true;
}
else if (usesUriStyleNodeCoreModules === undefined && unprefixedNodeCoreModules.has(moduleNameExpr.text)) {
// Avoid `unprefixedNodeCoreModules.has` for every import
usesUriStyleNodeCoreModules = false;
}
}
}
}

Просмотреть файл

@ -4866,11 +4866,14 @@ export interface Program extends ScriptReferenceHost {
*/
redirectTargetsMap: MultiMap<Path, string>;
/**
* Whether any (non-external, non-declaration) source files use `node:`-prefixed module specifiers.
* Whether any (non-external, non-declaration) source files use `node:`-prefixed module specifiers
* (except for those that are not available without the prefix).
* `false` indicates that an unprefixed builtin module was seen; `undefined` indicates that no
* builtin modules (or only modules exclusively available with the prefix) were seen.
*
* @internal
*/
readonly usesUriStyleNodeCoreModules: boolean;
readonly usesUriStyleNodeCoreModules: boolean | undefined;
/**
* Map from libFileName to actual resolved location of the lib
* @internal

Просмотреть файл

@ -11796,3 +11796,83 @@ export function isSideEffectImport(node: Node): boolean {
const ancestor = findAncestor(node, isImportDeclaration);
return !!ancestor && !ancestor.importClause;
}
// require('module').builtinModules.filter(x => !x.startsWith('_'))
const unprefixedNodeCoreModulesList = [
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"inspector/promises",
"module",
"net",
"os",
"path",
"path/posix",
"path/win32",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"readline/promises",
"repl",
"stream",
"stream/consumers",
"stream/promises",
"stream/web",
"string_decoder",
"sys",
"test/mock_loader",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"url",
"util",
"util/types",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib",
];
/** @internal */
export const unprefixedNodeCoreModules = new Set(unprefixedNodeCoreModulesList);
// await fetch('https://nodejs.org/docs/latest/api/all.json').then(r => r.text()).then(t =>
// new Set(t.match(/(?<=')node:.+?(?=')/g))
// .difference(new Set(require('module').builtinModules.map(x => `node:${x}`))))
/** @internal */
export const exclusivelyPrefixedNodeCoreModules = new Set([
"node:sea",
"node:sqlite",
"node:test",
"node:test/reporters",
]);
/** @internal */
export const nodeCoreModules = new Set([
...unprefixedNodeCoreModulesList,
...unprefixedNodeCoreModulesList.map(name => `node:${name}`),
...exclusivelyPrefixedNodeCoreModules,
]);

Просмотреть файл

@ -19,6 +19,7 @@ import {
hasJSFileExtension,
mapDefined,
MapLike,
nodeCoreModules,
normalizePath,
Path,
readConfigFile,
@ -61,64 +62,6 @@ export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVers
return availableVersion.compareTo(cachedTyping.version) <= 0;
}
const unprefixedNodeCoreModuleList = [
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"events",
"fs",
"fs/promises",
"http",
"https",
"http2",
"inspector",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"stream/promises",
"string_decoder",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"url",
"util",
"util/types",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib",
];
const prefixedNodeCoreModuleList = unprefixedNodeCoreModuleList.map(name => `node:${name}`);
/** @internal */
export const nodeCoreModuleList: readonly string[] = [...unprefixedNodeCoreModuleList, ...prefixedNodeCoreModuleList];
/** @internal */
export const nodeCoreModules = new Set(nodeCoreModuleList);
/** @internal */
export function nonRelativeModuleNameForTypingCache(moduleName: string) {
return nodeCoreModules.has(moduleName) ? "node" : moduleName;

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -10,7 +10,7 @@ import {
File,
} from "../helpers/virtualFileSystemWithWatch.js";
describe("unittests:: tsserver:: duplicate packages", () => {
describe("unittests:: tsserver:: duplicatePackages", () => {
// Tests that 'moduleSpecifiers.ts' will import from the redirecting file, and not from the file it redirects to, if that can provide a global module specifier.
it("works with import fixes", () => {
const packageContent = "export const foo: number;";

Просмотреть файл

@ -1455,7 +1455,7 @@ describe("unittests:: tsserver:: typingsInstaller:: discover typings", () => {
const { discoverTypings, baseline } = setup([f]);
const cache = new Map<string, ts.JsTyping.CachedTyping>();
for (const name of ts.JsTyping.nodeCoreModuleList) {
for (const name of ts.nodeCoreModules) {
discoverTypings(
[f.path],
ts.getDirectoryPath(f.path as ts.Path),

Просмотреть файл

@ -580,38 +580,6 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"https",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -644,6 +612,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"https",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -676,6 +676,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"inspector/promises",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -804,6 +836,70 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"path/posix",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"path/win32",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -964,6 +1060,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"readline/promises",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -1028,6 +1156,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"stream/consumers",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -1060,6 +1220,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"stream/web",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -1092,6 +1284,70 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"sys",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"test/mock_loader",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2084,38 +2340,6 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:https",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2148,6 +2372,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:https",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2180,6 +2436,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:inspector/promises",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2308,6 +2596,70 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:path/posix",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:path/win32",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2468,6 +2820,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:readline/promises",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2532,6 +2916,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:stream/consumers",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2564,6 +2980,38 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:stream/web",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -2596,6 +3044,70 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:sys",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:test/mock_loader",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
@ -3011,3 +3523,131 @@ TI:: [hh:mm:ss:mss] Finished typings discovery:
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:sea",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:sqlite",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:test",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}
ts.JsTyping.discoverTypings::
{
"fileNames": [
"/a/b/app.js"
],
"projectRootPath": "/a/b",
"safeList": {},
"packageNameToTypingLocation": {},
"typeAcquisition": {
"enable": true
},
"unresolvedImports": [
"node:test/reporters",
"somename"
],
"typesRegistry": {},
"compilerOptions": {}
}
TI:: [hh:mm:ss:mss] Inferred typings from unresolved imports: ["node","somename"]
TI:: [hh:mm:ss:mss] Finished typings discovery:
{
"cachedTypingPaths": [],
"newTypingNames": [
"node",
"somename"
],
"filesToWatch": [
"/a/b/bower_components",
"/a/b/node_modules"
]
}

Просмотреть файл

@ -18,11 +18,21 @@ verify.completions({
source: "fs",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "node:fs",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "fs/promises",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "node:fs/promises",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}]),
preferences: {
includeCompletionsForModuleExports: true,

Просмотреть файл

@ -31,6 +31,15 @@
//// import "path";
//// write/*mixed2*/
// @Filename: /test1.ts
//// import "node:test";
//// import "path";
//// writeFile/*test1*/
// @Filename: /test2.ts
//// import "node:test";
//// writeFile/*test2*/
verify.completions({
marker: "noPrefix",
exact: completion.globalsPlus([{
@ -67,20 +76,18 @@ verify.completions({
},
});
// We're doing as little work as possible to decide which module specifiers
// to use, so we just take the *first* recognized node core module in the file
// and copy its style.
// Prefixed imports take precedence over non-prefixed imports when mixed
verify.completions({
marker: "mixed1",
exact: completion.globalsPlus([{
name: "writeFile",
source: "fs",
source: "node:fs",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "fs/promises",
source: "node:fs/promises",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}]),
@ -106,3 +113,44 @@ verify.completions({
includeCompletionsForModuleExports: true,
},
});
// Unless the prefixed import is not available unprefixed
verify.importFixModuleSpecifiers("test1", ["fs", "fs/promises"]);
verify.importFixModuleSpecifiers("test2", ["node:fs", "node:fs/promises"]);
verify.completions({
marker: "test1",
exact: completion.globalsPlus([{
name: "writeFile",
source: "fs",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "fs/promises",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}]),
preferences: {
includeCompletionsForModuleExports: true,
},
});
verify.completions({
marker: "test2",
exact: completion.globalsPlus([{
name: "writeFile",
source: "node:fs",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}, {
name: "writeFile",
source: "node:fs/promises",
hasAction: true,
sortText: completion.SortText.AutoImportSuggestions
}]),
preferences: {
includeCompletionsForModuleExports: true,
},
});

Просмотреть файл

@ -14,7 +14,7 @@
// @Filename: /index.ts
//// writeFile/**/
verify.importFixModuleSpecifiers("", ["node:fs", "node:fs/promises", "fs", "fs/promises"]);
verify.importFixModuleSpecifiers("", ["node:fs", "node:fs/promises"]);
goTo.file("/other.ts");
edit.replaceLine(0, "\n");
@ -26,4 +26,4 @@ goTo.file("/other.ts");
edit.replaceLine(0, `import "node:fs/promises";\n`);
goTo.file("/index.ts");
verify.importFixModuleSpecifiers("", ["node:fs", "node:fs/promises", "fs", "fs/promises"]);
verify.importFixModuleSpecifiers("", ["node:fs", "node:fs/promises"]);

Просмотреть файл

@ -31,12 +31,24 @@
//// import "path";
//// writeFile/*mixed2*/
verify.importFixModuleSpecifiers("noPrefix", ["fs", "fs/promises", "node:fs", "node:fs/promises"]);
verify.importFixModuleSpecifiers("prefix", ["node:fs", "node:fs/promises", "fs", "fs/promises"]);
// @Filename: /test1.ts
//// import "node:test";
//// import "path";
//// writeFile/*test1*/
// We're doing as little work as possible to decide which module specifiers
// to use, so we just take the *first* recognized node core module in the file
// and copy its style.
// @Filename: /test2.ts
//// import "node:test";
//// writeFile/*test2*/
verify.importFixModuleSpecifiers("mixed1", ["fs", "fs/promises", "node:fs", "node:fs/promises"]);
verify.importFixModuleSpecifiers("mixed2", ["node:fs", "node:fs/promises", "fs", "fs/promises"]);
verify.importFixModuleSpecifiers("noPrefix", ["fs", "fs/promises"]);
verify.importFixModuleSpecifiers("prefix", ["node:fs", "node:fs/promises"]);
// Prefixed imports take precedence over non-prefixed imports when mixed
verify.importFixModuleSpecifiers("mixed1", ["node:fs", "node:fs/promises"]);
verify.importFixModuleSpecifiers("mixed2", ["node:fs", "node:fs/promises"]);
// Unless the prefixed import is not available unprefixed
verify.importFixModuleSpecifiers("test1", ["fs", "fs/promises"]);
verify.importFixModuleSpecifiers("test2", ["node:fs", "node:fs/promises"]);