mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Make AutoImportProviderProject work with symlinked monorepos (#39679)
* Hack everything together * Add test * Remove realpath from program * Ensure symlinked directories are directories * Revert unnecessary change * Update baselines * Use host program realpath on AutoImportProviderProject files before program creation * Which fixes hasRoots() too * Apply suggestions from code review Co-authored-by: Sheetal Nandi <shkamat@microsoft.com> * Lint Co-authored-by: Sheetal Nandi <shkamat@microsoft.com>
This commit is contained in:
co-authored by
Sheetal Nandi
parent
312a6f0efb
commit
ec33814616
@@ -4237,7 +4237,7 @@ namespace ts {
|
||||
getCommonSourceDirectory: !!(host as Program).getCommonSourceDirectory ? () => (host as Program).getCommonSourceDirectory() : () => "",
|
||||
getSourceFiles: () => host.getSourceFiles(),
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
getProbableSymlinks: maybeBind(host, host.getProbableSymlinks),
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
redirectTargetsMap: host.redirectTargetsMap,
|
||||
getProjectReferenceRedirect: fileName => host.getProjectReferenceRedirect(fileName),
|
||||
|
||||
@@ -185,20 +185,22 @@ namespace ts.moduleSpecifiers {
|
||||
const result = forEach(targets, cb);
|
||||
if (result) return result;
|
||||
}
|
||||
const links = host.getProbableSymlinks
|
||||
? host.getProbableSymlinks(host.getSourceFiles())
|
||||
const links = host.getSymlinkCache
|
||||
? host.getSymlinkCache()
|
||||
: discoverProbableSymlinks(host.getSourceFiles(), getCanonicalFileName, cwd);
|
||||
|
||||
const symlinkedDirectories = links.getSymlinkedDirectories();
|
||||
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
|
||||
const result = forEachEntry(links, (resolved, path) => {
|
||||
if (startsWithDirectory(importingFileName, resolved, getCanonicalFileName)) {
|
||||
const result = symlinkedDirectories && forEachEntry(symlinkedDirectories, (resolved, path) => {
|
||||
if (resolved === false) return undefined;
|
||||
if (startsWithDirectory(importingFileName, resolved.realPath, getCanonicalFileName)) {
|
||||
return undefined; // Don't want to a package to globally import from itself
|
||||
}
|
||||
|
||||
const target = find(targets, t => compareStrings(t.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo);
|
||||
const target = find(targets, t => compareStrings(t.slice(0, resolved.real.length), resolved.real) === Comparison.EqualTo);
|
||||
if (target === undefined) return undefined;
|
||||
|
||||
const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName);
|
||||
const relative = getRelativePathFromDirectory(resolved.real, target, getCanonicalFileName);
|
||||
const option = resolvePath(path, relative);
|
||||
if (!host.fileExists || host.fileExists(option)) {
|
||||
const result = cb(option);
|
||||
|
||||
+23
-25
@@ -702,7 +702,7 @@ namespace ts {
|
||||
let processingDefaultLibFiles: SourceFile[] | undefined;
|
||||
let processingOtherFiles: SourceFile[] | undefined;
|
||||
let files: SourceFile[];
|
||||
let symlinks: ReadonlyESMap<string, string> | undefined;
|
||||
let symlinks: SymlinkCache | undefined;
|
||||
let commonSourceDirectory: string;
|
||||
let diagnosticsProducingTypeChecker: TypeChecker;
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
@@ -811,8 +811,9 @@ namespace ts {
|
||||
|
||||
const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect?.() &&
|
||||
!options.disableSourceOfProjectReferenceRedirect;
|
||||
const { onProgramCreateComplete, fileExists } = updateHostForUseSourceOfProjectReferenceRedirect({
|
||||
const { onProgramCreateComplete, fileExists, directoryExists } = updateHostForUseSourceOfProjectReferenceRedirect({
|
||||
compilerHost: host,
|
||||
getSymlinkCache,
|
||||
useSourceOfProjectReferenceRedirect,
|
||||
toPath,
|
||||
getResolvedProjectReferences,
|
||||
@@ -974,7 +975,9 @@ namespace ts {
|
||||
isSourceOfProjectReferenceRedirect,
|
||||
emitBuildInfo,
|
||||
fileExists,
|
||||
getProbableSymlinks,
|
||||
directoryExists,
|
||||
getSymlinkCache,
|
||||
realpath: host.realpath?.bind(host),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
};
|
||||
|
||||
@@ -1490,7 +1493,7 @@ namespace ts {
|
||||
getResolvedProjectReferenceToRedirect,
|
||||
getProjectReferenceRedirect,
|
||||
isSourceOfProjectReferenceRedirect,
|
||||
getProbableSymlinks,
|
||||
getSymlinkCache,
|
||||
writeFile: writeFileCallback || (
|
||||
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
|
||||
isEmitBlocked,
|
||||
@@ -3468,9 +3471,9 @@ namespace ts {
|
||||
return comparePaths(file1, file2, currentDirectory, !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
|
||||
}
|
||||
|
||||
function getProbableSymlinks(): ReadonlyESMap<string, string> {
|
||||
if (host.getSymlinks) {
|
||||
return host.getSymlinks();
|
||||
function getSymlinkCache(): SymlinkCache {
|
||||
if (host.getSymlinkCache) {
|
||||
return host.getSymlinkCache();
|
||||
}
|
||||
return symlinks || (symlinks = discoverProbableSymlinks(
|
||||
files,
|
||||
@@ -3479,13 +3482,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
interface SymlinkedDirectory {
|
||||
real: string;
|
||||
realPath: Path;
|
||||
}
|
||||
|
||||
interface HostForUseSourceOfProjectReferenceRedirect {
|
||||
compilerHost: CompilerHost;
|
||||
getSymlinkCache: () => SymlinkCache;
|
||||
useSourceOfProjectReferenceRedirect: boolean;
|
||||
toPath(fileName: string): Path;
|
||||
getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
|
||||
@@ -3495,9 +3494,6 @@ namespace ts {
|
||||
|
||||
function updateHostForUseSourceOfProjectReferenceRedirect(host: HostForUseSourceOfProjectReferenceRedirect) {
|
||||
let setOfDeclarationDirectories: Set<Path> | undefined;
|
||||
let symlinkedDirectories: ESMap<Path, SymlinkedDirectory | false> | undefined;
|
||||
let symlinkedFiles: ESMap<Path, string> | undefined;
|
||||
|
||||
const originalFileExists = host.compilerHost.fileExists;
|
||||
const originalDirectoryExists = host.compilerHost.directoryExists;
|
||||
const originalGetDirectories = host.compilerHost.getDirectories;
|
||||
@@ -3507,11 +3503,12 @@ namespace ts {
|
||||
|
||||
host.compilerHost.fileExists = fileExists;
|
||||
|
||||
let directoryExists;
|
||||
if (originalDirectoryExists) {
|
||||
// This implementation of directoryExists checks if the directory being requested is
|
||||
// directory of .d.ts file for the referenced Project.
|
||||
// If it is it returns true irrespective of whether that directory exists on host
|
||||
host.compilerHost.directoryExists = path => {
|
||||
directoryExists = host.compilerHost.directoryExists = path => {
|
||||
if (originalDirectoryExists.call(host.compilerHost, path)) {
|
||||
handleDirectoryCouldBeSymlink(path);
|
||||
return true;
|
||||
@@ -3553,11 +3550,11 @@ namespace ts {
|
||||
// This is something we keep for life time of the host
|
||||
if (originalRealpath) {
|
||||
host.compilerHost.realpath = s =>
|
||||
symlinkedFiles?.get(host.toPath(s)) ||
|
||||
host.getSymlinkCache().getSymlinkedFiles()?.get(host.toPath(s)) ||
|
||||
originalRealpath.call(host.compilerHost, s);
|
||||
}
|
||||
|
||||
return { onProgramCreateComplete, fileExists };
|
||||
return { onProgramCreateComplete, fileExists, directoryExists };
|
||||
|
||||
function onProgramCreateComplete() {
|
||||
host.compilerHost.fileExists = originalFileExists;
|
||||
@@ -3603,20 +3600,20 @@ namespace ts {
|
||||
|
||||
// Because we already watch node_modules, handle symlinks in there
|
||||
if (!originalRealpath || !stringContains(directory, nodeModulesPathPart)) return;
|
||||
if (!symlinkedDirectories) symlinkedDirectories = new Map();
|
||||
const symlinkCache = host.getSymlinkCache();
|
||||
const directoryPath = ensureTrailingDirectorySeparator(host.toPath(directory));
|
||||
if (symlinkedDirectories.has(directoryPath)) return;
|
||||
if (symlinkCache.getSymlinkedDirectories()?.has(directoryPath)) return;
|
||||
|
||||
const real = normalizePath(originalRealpath.call(host.compilerHost, directory));
|
||||
let realPath: Path;
|
||||
if (real === directory ||
|
||||
(realPath = ensureTrailingDirectorySeparator(host.toPath(real))) === directoryPath) {
|
||||
// not symlinked
|
||||
symlinkedDirectories.set(directoryPath, false);
|
||||
symlinkCache.setSymlinkedDirectory(directoryPath, false);
|
||||
return;
|
||||
}
|
||||
|
||||
symlinkedDirectories.set(directoryPath, {
|
||||
symlinkCache.setSymlinkedDirectory(directoryPath, {
|
||||
real: ensureTrailingDirectorySeparator(real),
|
||||
realPath
|
||||
});
|
||||
@@ -3630,10 +3627,12 @@ namespace ts {
|
||||
const result = fileOrDirectoryExistsUsingSource(fileOrDirectory);
|
||||
if (result !== undefined) return result;
|
||||
|
||||
const symlinkCache = host.getSymlinkCache();
|
||||
const symlinkedDirectories = symlinkCache.getSymlinkedDirectories();
|
||||
if (!symlinkedDirectories) return false;
|
||||
const fileOrDirectoryPath = host.toPath(fileOrDirectory);
|
||||
if (!stringContains(fileOrDirectoryPath, nodeModulesPathPart)) return false;
|
||||
if (isFile && symlinkedFiles && symlinkedFiles.has(fileOrDirectoryPath)) return true;
|
||||
if (isFile && symlinkCache.getSymlinkedFiles()?.has(fileOrDirectoryPath)) return true;
|
||||
|
||||
// If it contains node_modules check if its one of the symlinked path we know of
|
||||
return firstDefinedIterator(
|
||||
@@ -3642,10 +3641,9 @@ namespace ts {
|
||||
if (!symlinkedDirectory || !startsWith(fileOrDirectoryPath, directoryPath)) return undefined;
|
||||
const result = fileOrDirectoryExistsUsingSource(fileOrDirectoryPath.replace(directoryPath, symlinkedDirectory.realPath));
|
||||
if (isFile && result) {
|
||||
if (!symlinkedFiles) symlinkedFiles = new Map();
|
||||
// Store the real path for the file'
|
||||
const absolutePath = getNormalizedAbsolutePath(fileOrDirectory, host.compilerHost.getCurrentDirectory());
|
||||
symlinkedFiles.set(
|
||||
symlinkCache.setSymlinkedFile(
|
||||
fileOrDirectoryPath,
|
||||
`${symlinkedDirectory.real}${absolutePath.replace(new RegExp(directoryPath, "i"), "")}`
|
||||
);
|
||||
|
||||
@@ -3767,7 +3767,6 @@ namespace ts {
|
||||
/*@internal*/ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
/*@internal*/ getProgramBuildInfo?(): ProgramBuildInfo | undefined;
|
||||
/*@internal*/ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
/*@internal*/ getProbableSymlinks(): ReadonlyESMap<string, string>;
|
||||
/**
|
||||
* This implementation handles file exists to be true if file is source of project reference redirect when program is created using useSourceOfProjectReferenceRedirect
|
||||
*/
|
||||
@@ -6243,7 +6242,7 @@ namespace ts {
|
||||
|
||||
// TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base
|
||||
/*@internal*/createDirectory?(directory: string): void;
|
||||
/*@internal*/getSymlinks?(): ReadonlyESMap<string, string>;
|
||||
/*@internal*/getSymlinkCache?(): SymlinkCache;
|
||||
}
|
||||
|
||||
/** true if --out otherwise source file name */
|
||||
@@ -7757,8 +7756,10 @@ namespace ts {
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
fileExists(path: string): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
directoryExists?(path: string): boolean;
|
||||
readFile?(path: string): string | undefined;
|
||||
getProbableSymlinks?(files: readonly SourceFile[]): ReadonlyESMap<string, string>;
|
||||
realpath?(path: string): string;
|
||||
getSymlinkCache?(): SymlinkCache;
|
||||
getGlobalTypingsCacheLocation?(): string | undefined;
|
||||
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
|
||||
@@ -5926,28 +5926,57 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
export function discoverProbableSymlinks(files: readonly SourceFile[], getCanonicalFileName: GetCanonicalFileName, cwd: string): ReadonlyESMap<string, string> {
|
||||
const result = new Map<string, string>();
|
||||
export interface SymlinkedDirectory {
|
||||
real: string;
|
||||
realPath: Path;
|
||||
}
|
||||
|
||||
export interface SymlinkCache {
|
||||
getSymlinkedDirectories(): ReadonlyESMap<Path, SymlinkedDirectory | false> | undefined;
|
||||
getSymlinkedFiles(): ReadonlyESMap<Path, string> | undefined;
|
||||
setSymlinkedDirectory(path: Path, directory: SymlinkedDirectory | false): void;
|
||||
setSymlinkedFile(path: Path, real: string): void;
|
||||
}
|
||||
|
||||
export function createSymlinkCache(): SymlinkCache {
|
||||
let symlinkedDirectories: ESMap<Path, SymlinkedDirectory | false> | undefined;
|
||||
let symlinkedFiles: ESMap<Path, string> | undefined;
|
||||
return {
|
||||
getSymlinkedFiles: () => symlinkedFiles,
|
||||
getSymlinkedDirectories: () => symlinkedDirectories,
|
||||
setSymlinkedFile: (path, real) => (symlinkedFiles || (symlinkedFiles = new Map())).set(path, real),
|
||||
setSymlinkedDirectory: (path, directory) => (symlinkedDirectories || (symlinkedDirectories = new Map())).set(path, directory),
|
||||
};
|
||||
}
|
||||
|
||||
export function discoverProbableSymlinks(files: readonly SourceFile[], getCanonicalFileName: GetCanonicalFileName, cwd: string): SymlinkCache {
|
||||
const cache = createSymlinkCache();
|
||||
const symlinks = flatten<readonly [string, string]>(mapDefined(files, sf =>
|
||||
sf.resolvedModules && compact(arrayFrom(mapIterator(sf.resolvedModules.values(), res =>
|
||||
res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] as const : undefined)))));
|
||||
for (const [resolvedPath, originalPath] of symlinks) {
|
||||
const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedPath, originalPath, cwd, getCanonicalFileName);
|
||||
result.set(commonOriginal, commonResolved);
|
||||
const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedPath, originalPath, cwd, getCanonicalFileName) || emptyArray;
|
||||
if (commonResolved && commonOriginal) {
|
||||
cache.setSymlinkedDirectory(
|
||||
toPath(commonOriginal, cwd, getCanonicalFileName),
|
||||
{ real: commonResolved, realPath: toPath(commonResolved, cwd, getCanonicalFileName) });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return cache;
|
||||
}
|
||||
|
||||
function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFileName: GetCanonicalFileName): [string, string] {
|
||||
function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFileName: GetCanonicalFileName): [string, string] | undefined {
|
||||
const aParts = getPathComponents(toPath(a, cwd, getCanonicalFileName));
|
||||
const bParts = getPathComponents(toPath(b, cwd, getCanonicalFileName));
|
||||
let isDirectory = false;
|
||||
while (!isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) &&
|
||||
!isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) &&
|
||||
getCanonicalFileName(aParts[aParts.length - 1]) === getCanonicalFileName(bParts[bParts.length - 1])) {
|
||||
aParts.pop();
|
||||
bParts.pop();
|
||||
isDirectory = true;
|
||||
}
|
||||
return [getPathFromPathComponents(aParts), getPathFromPathComponents(bParts)];
|
||||
return isDirectory ? [getPathFromPathComponents(aParts), getPathFromPathComponents(bParts)] : undefined;
|
||||
}
|
||||
|
||||
// KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink.
|
||||
|
||||
@@ -154,6 +154,19 @@ namespace Harness.LanguageService {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
public realpath(path: string): string {
|
||||
try {
|
||||
return this.vfs.realpathSync(path);
|
||||
}
|
||||
catch {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public directoryExists(path: string) {
|
||||
return this.vfs.statSync(path).isDirectory();
|
||||
}
|
||||
|
||||
public getScriptInfo(fileName: string): ScriptInfo | undefined {
|
||||
return this.scriptInfos.get(vpath.resolve(this.vfs.cwd(), fileName));
|
||||
}
|
||||
@@ -720,10 +733,15 @@ namespace Harness.LanguageService {
|
||||
fileName = Compiler.defaultLibFileName;
|
||||
}
|
||||
|
||||
const snapshot = this.host.getScriptSnapshot(fileName);
|
||||
// System FS would follow symlinks, even though snapshots are stored by original file name
|
||||
const snapshot = this.host.getScriptSnapshot(fileName) || this.host.getScriptSnapshot(this.realpath(fileName));
|
||||
return snapshot && ts.getSnapshotText(snapshot);
|
||||
}
|
||||
|
||||
realpath(path: string) {
|
||||
return this.host.realpath(path);
|
||||
}
|
||||
|
||||
writeFile = ts.noop;
|
||||
|
||||
resolvePath(path: string): string {
|
||||
@@ -731,7 +749,7 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
|
||||
fileExists(path: string): boolean {
|
||||
return !!this.host.getScriptSnapshot(path);
|
||||
return this.host.fileExists(path);
|
||||
}
|
||||
|
||||
directoryExists(): boolean {
|
||||
|
||||
+44
-8
@@ -246,7 +246,7 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
private dirtyFilesForSuggestions: Set<Path> | undefined;
|
||||
/*@internal*/
|
||||
private symlinks: ReadonlyESMap<string, string> | undefined;
|
||||
private symlinks: SymlinkCache | undefined;
|
||||
/*@internal*/
|
||||
autoImportProviderHost: AutoImportProviderProject | false | undefined;
|
||||
|
||||
@@ -328,9 +328,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getProbableSymlinks(files: readonly SourceFile[]): ReadonlyESMap<string, string> {
|
||||
getSymlinkCache(): SymlinkCache {
|
||||
return this.symlinks || (this.symlinks = discoverProbableSymlinks(
|
||||
files,
|
||||
this.program?.getSourceFiles() || emptyArray,
|
||||
this.getCanonicalFileName,
|
||||
this.getCurrentDirectory()));
|
||||
}
|
||||
@@ -1640,6 +1640,22 @@ namespace ts.server {
|
||||
return this.projectService.includePackageJsonAutoImports();
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getModuleResolutionHostForAutoImportProvider(): ModuleResolutionHost {
|
||||
if (this.program) {
|
||||
return {
|
||||
fileExists: this.program.fileExists,
|
||||
directoryExists: this.program.directoryExists,
|
||||
realpath: this.program.realpath || this.projectService.host.realpath?.bind(this.projectService.host),
|
||||
getCurrentDirectory: this.getCurrentDirectory.bind(this),
|
||||
readFile: this.projectService.host.readFile.bind(this.projectService.host),
|
||||
getDirectories: this.projectService.host.getDirectories.bind(this.projectService.host),
|
||||
trace: this.projectService.host.trace?.bind(this.projectService.host),
|
||||
};
|
||||
}
|
||||
return this.projectService.host;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getPackageJsonAutoImportProvider(): Program | undefined {
|
||||
if (this.autoImportProviderHost === false) {
|
||||
@@ -1657,7 +1673,7 @@ namespace ts.server {
|
||||
|
||||
const dependencySelection = this.includePackageJsonAutoImports();
|
||||
if (dependencySelection) {
|
||||
this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.projectService.host, this.documentRegistry);
|
||||
this.autoImportProviderHost = AutoImportProviderProject.create(dependencySelection, this, this.getModuleResolutionHostForAutoImportProvider(), this.documentRegistry);
|
||||
if (this.autoImportProviderHost) {
|
||||
updateProjectIfDirty(this.autoImportProviderHost);
|
||||
return this.autoImportProviderHost.getCurrentProgram();
|
||||
@@ -1841,8 +1857,11 @@ namespace ts.server {
|
||||
moduleResolutionHost));
|
||||
|
||||
for (const resolution of resolutions) {
|
||||
if (resolution.resolvedTypeReferenceDirective?.resolvedFileName && !hostProject.getCurrentProgram()!.getSourceFile(resolution.resolvedTypeReferenceDirective.resolvedFileName)) {
|
||||
rootNames = append(rootNames, resolution.resolvedTypeReferenceDirective.resolvedFileName);
|
||||
if (!resolution.resolvedTypeReferenceDirective?.resolvedFileName) continue;
|
||||
const { resolvedFileName } = resolution.resolvedTypeReferenceDirective;
|
||||
const fileName = moduleResolutionHost.realpath?.(resolvedFileName) || resolvedFileName;
|
||||
if (!hostProject.getCurrentProgram()!.getSourceFile(fileName) && !hostProject.getCurrentProgram()!.getSourceFile(resolvedFileName)) {
|
||||
rootNames = append(rootNames, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1869,7 +1888,7 @@ namespace ts.server {
|
||||
skipLibCheck: true,
|
||||
types: ts.emptyArray,
|
||||
lib: ts.emptyArray,
|
||||
sourceMap: false
|
||||
sourceMap: false,
|
||||
};
|
||||
|
||||
const rootNames = this.getRootFileNames(dependencySelection, hostProject, moduleResolutionHost, compilerOptions);
|
||||
@@ -1914,7 +1933,7 @@ namespace ts.server {
|
||||
rootFileNames = AutoImportProviderProject.getRootFileNames(
|
||||
this.hostProject.includePackageJsonAutoImports(),
|
||||
this.hostProject,
|
||||
this.projectService.host,
|
||||
this.hostProject.getModuleResolutionHostForAutoImportProvider(),
|
||||
this.getCompilationSettings());
|
||||
}
|
||||
|
||||
@@ -1941,6 +1960,18 @@ namespace ts.server {
|
||||
throw new Error("AutoImportProviderProject is an auto import provider; use `markAsDirty()` instead.");
|
||||
}
|
||||
|
||||
getModuleResolutionHostForAutoImportProvider(): never {
|
||||
throw new Error("AutoImportProviderProject cannot provide its own host; use `hostProject.getModuleResolutionHostForAutomImportProvider()` instead.");
|
||||
}
|
||||
|
||||
getProjectReferences() {
|
||||
return this.hostProject.getProjectReferences();
|
||||
}
|
||||
|
||||
useSourceOfProjectReferenceRedirect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
includePackageJsonAutoImports() {
|
||||
return PackageJsonAutoImportPreference.None;
|
||||
@@ -1949,6 +1980,11 @@ namespace ts.server {
|
||||
getTypeAcquisition(): TypeAcquisition {
|
||||
return { enable: false };
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getSymlinkCache() {
|
||||
return this.hostProject.getSymlinkCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1296,6 +1296,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
fileExists,
|
||||
readFile,
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache),
|
||||
realpath: maybeBind(host, host.realpath),
|
||||
directoryExists: directoryName => {
|
||||
return directoryProbablyExists(directoryName, host);
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
getGlobalTypingsCacheLocation?(): string | undefined;
|
||||
/* @internal */
|
||||
getProbableSymlinks?(files: readonly SourceFile[]): ReadonlyESMap<string, string>;
|
||||
getSymlinkCache?(files?: readonly SourceFile[]): SymlinkCache;
|
||||
|
||||
/*
|
||||
* Required for full import and type reference completions.
|
||||
|
||||
@@ -1760,7 +1760,7 @@ namespace ts {
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
readFile: maybeBind(host, host.readFile),
|
||||
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
||||
getProbableSymlinks: maybeBind(host, host.getProbableSymlinks) || (() => program.getProbableSymlinks()),
|
||||
getSymlinkCache: maybeBind(host, host.getSymlinkCache) || program.getSymlinkCache,
|
||||
getGlobalTypingsCacheLocation: maybeBind(host, host.getGlobalTypingsCacheLocation),
|
||||
getSourceFiles: () => program.getSourceFiles(),
|
||||
redirectTargetsMap: program.redirectTargetsMap,
|
||||
|
||||
@@ -9269,6 +9269,9 @@ declare namespace ts.server {
|
||||
getScriptFileNames(): string[];
|
||||
getLanguageService(): never;
|
||||
markAutoImportProviderAsDirty(): never;
|
||||
getModuleResolutionHostForAutoImportProvider(): never;
|
||||
getProjectReferences(): readonly ProjectReference[] | undefined;
|
||||
useSourceOfProjectReferenceRedirect(): boolean;
|
||||
getTypeAcquisition(): TypeAcquisition;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/// <reference path="../fourslash.ts" />
|
||||
|
||||
// @Filename: /a/package.json
|
||||
//// { "dependencies": { "b": "*" } }
|
||||
|
||||
// @Filename: /a/tsconfig.json
|
||||
//// { "compilerOptions": { "module": "commonjs", "target": "esnext" }, "references": [{ "path": "../b" }] }
|
||||
|
||||
// @Filename: /a/index.ts
|
||||
//// new Shape/**/
|
||||
|
||||
// @Filename: /b/package.json
|
||||
//// { "types": "out/index.d.ts" }
|
||||
|
||||
// @Filename: /b/tsconfig.json
|
||||
//// { "compilerOptions": { "outDir": "out", "composite": true } }
|
||||
|
||||
// @Filename: /b/index.ts
|
||||
//// export class Shape {}
|
||||
|
||||
// @link: /b -> /a/node_modules/b
|
||||
|
||||
goTo.marker();
|
||||
verify.importFixAtPosition([`import { Shape } from "b";\r\n\r\nnew Shape`]);
|
||||
Reference in New Issue
Block a user