mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Dont open composite projects to determine if script info is part of project (#59688)
This commit is contained in:
@@ -3250,13 +3250,25 @@ function shouldReportNoInputFiles(fileNames: string[], canJsonReportNoInutFiles:
|
||||
return fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isSolutionConfig(config: ParsedCommandLine): boolean {
|
||||
return !config.fileNames.length &&
|
||||
hasProperty(config.raw, "references");
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function canJsonReportNoInputFiles(raw: any): boolean {
|
||||
return !hasProperty(raw, "files") && !hasProperty(raw, "references");
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function updateErrorForNoInputFiles(fileNames: string[], configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean): boolean {
|
||||
export function updateErrorForNoInputFiles(
|
||||
fileNames: string[],
|
||||
configFileName: string,
|
||||
configFileSpecs: ConfigFileSpecs,
|
||||
configParseDiagnostics: Diagnostic[],
|
||||
canJsonReportNoInutFiles: boolean,
|
||||
): boolean {
|
||||
const existingErrors = configParseDiagnostics.length;
|
||||
if (shouldReportNoInputFiles(fileNames, canJsonReportNoInutFiles)) {
|
||||
configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName));
|
||||
@@ -3960,13 +3972,14 @@ export function matchesExclude(
|
||||
);
|
||||
}
|
||||
|
||||
function matchesExcludeWorker(
|
||||
/** @internal */
|
||||
export function matchesExcludeWorker(
|
||||
pathToCheck: string,
|
||||
excludeSpecs: readonly string[] | undefined,
|
||||
useCaseSensitiveFileNames: boolean,
|
||||
currentDirectory: string,
|
||||
basePath?: string,
|
||||
) {
|
||||
): boolean {
|
||||
const excludePattern = getRegularExpressionForWildcard(excludeSpecs, combinePaths(normalizePath(currentDirectory), basePath), "exclude");
|
||||
const excludeRegex = excludePattern && getRegexFromPattern(excludePattern, useCaseSensitiveFileNames);
|
||||
if (!excludeRegex) return false;
|
||||
|
||||
+66
-38
@@ -1150,7 +1150,11 @@ export function forEachResolvedProjectReference<T>(
|
||||
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
|
||||
cb: (resolvedProjectReference: ResolvedProjectReference, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
return forEachProjectReference(/*projectReferences*/ undefined, resolvedProjectReferences, (resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent));
|
||||
return forEachProjectReference(
|
||||
/*projectReferences*/ undefined,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent) => resolvedRef && cb(resolvedRef, parent),
|
||||
);
|
||||
}
|
||||
|
||||
function forEachProjectReference<T>(
|
||||
@@ -1160,7 +1164,6 @@ function forEachProjectReference<T>(
|
||||
cbRef?: (projectReferences: readonly ProjectReference[] | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
|
||||
): T | undefined {
|
||||
let seenResolvedRefs: Set<Path> | undefined;
|
||||
|
||||
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined);
|
||||
|
||||
function worker(
|
||||
@@ -1173,19 +1176,26 @@ function forEachProjectReference<T>(
|
||||
const result = cbRef(projectReferences, parent);
|
||||
if (result) return result;
|
||||
}
|
||||
|
||||
return forEach(resolvedProjectReferences, (resolvedRef, index) => {
|
||||
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
|
||||
// ignore recursives
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = cbResolvedRef(resolvedRef, parent, index);
|
||||
if (result || !resolvedRef) return result;
|
||||
|
||||
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
|
||||
return worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef);
|
||||
});
|
||||
let skipChildren: Set<ResolvedProjectReference> | undefined;
|
||||
return forEach(
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, index) => {
|
||||
if (resolvedRef && seenResolvedRefs?.has(resolvedRef.sourceFile.path)) {
|
||||
(skipChildren ??= new Set()).add(resolvedRef);
|
||||
// ignore recursives
|
||||
return undefined;
|
||||
}
|
||||
const result = cbResolvedRef(resolvedRef, parent, index);
|
||||
if (result || !resolvedRef) return result;
|
||||
(seenResolvedRefs ||= new Set()).add(resolvedRef.sourceFile.path);
|
||||
},
|
||||
) || forEach(
|
||||
resolvedProjectReferences,
|
||||
resolvedRef =>
|
||||
resolvedRef && !skipChildren?.has(resolvedRef) ?
|
||||
worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef) :
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1367,7 +1377,14 @@ export function isProgramUptoDate(
|
||||
(seenResolvedRefs || (seenResolvedRefs = [])).push(oldResolvedRef);
|
||||
|
||||
// If child project references are upto date, this project reference is uptodate
|
||||
return !forEach(oldResolvedRef.references, (childResolvedRef, index) => !resolvedProjectReferenceUptoDate(childResolvedRef, oldResolvedRef.commandLine.projectReferences![index]));
|
||||
return !forEach(
|
||||
oldResolvedRef.references,
|
||||
(childResolvedRef, index) =>
|
||||
!resolvedProjectReferenceUptoDate(
|
||||
childResolvedRef,
|
||||
oldResolvedRef.commandLine.projectReferences![index],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// In old program, not able to resolve project reference path,
|
||||
@@ -4905,7 +4922,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
case FileIncludeKind.SourceFromProjectReference:
|
||||
case FileIncludeKind.OutputFromProjectReference:
|
||||
const referencedResolvedRef = Debug.checkDefined(resolvedProjectReferences?.[reason.index]);
|
||||
const referenceInfo = forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => resolvedRef === referencedResolvedRef ? { sourceFile: parent?.sourceFile || options.configFile!, index } : undefined);
|
||||
const referenceInfo = forEachProjectReference(
|
||||
projectReferences,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent, index) =>
|
||||
resolvedRef === referencedResolvedRef ?
|
||||
{ sourceFile: parent?.sourceFile || options.configFile!, index } :
|
||||
undefined,
|
||||
);
|
||||
if (!referenceInfo) return undefined;
|
||||
const { sourceFile, index } = referenceInfo;
|
||||
const referencesSyntax = forEachTsConfigPropArray(sourceFile as TsConfigSourceFile, "references", property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined);
|
||||
@@ -4945,28 +4969,32 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
function verifyProjectReferences() {
|
||||
const buildInfoPath = !options.suppressOutputPathCheck ? getTsBuildInfoEmitOutputFilePath(options) : undefined;
|
||||
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, parent, index) => {
|
||||
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
|
||||
const parentFile = parent && parent.sourceFile as JsonSourceFile;
|
||||
verifyDeprecatedProjectReference(ref, parentFile, index);
|
||||
if (!resolvedRef) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
|
||||
return;
|
||||
}
|
||||
const options = resolvedRef.commandLine.options;
|
||||
if (!options.composite || options.noEmit) {
|
||||
// ok to not have composite if the current program is container only
|
||||
const inputs = parent ? parent.commandLine.fileNames : rootNames;
|
||||
if (inputs.length) {
|
||||
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
|
||||
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
|
||||
forEachProjectReference(
|
||||
projectReferences,
|
||||
resolvedProjectReferences,
|
||||
(resolvedRef, parent, index) => {
|
||||
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
|
||||
const parentFile = parent && parent.sourceFile as JsonSourceFile;
|
||||
verifyDeprecatedProjectReference(ref, parentFile, index);
|
||||
if (!resolvedRef) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.File_0_not_found, ref.path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
|
||||
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
|
||||
}
|
||||
});
|
||||
const options = resolvedRef.commandLine.options;
|
||||
if (!options.composite || options.noEmit) {
|
||||
// ok to not have composite if the current program is container only
|
||||
const inputs = parent ? parent.commandLine.fileNames : rootNames;
|
||||
if (inputs.length) {
|
||||
if (!options.composite) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
|
||||
if (options.noEmit) createDiagnosticForReference(parentFile, index, Diagnostics.Referenced_project_0_may_not_disable_emit, ref.path);
|
||||
}
|
||||
}
|
||||
if (!parent && buildInfoPath && buildInfoPath === getTsBuildInfoEmitOutputFilePath(options)) {
|
||||
createDiagnosticForReference(parentFile, index, Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoPath, ref.path);
|
||||
hasEmitBlockingDiagnostics.set(toPath(buildInfoPath), true);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) {
|
||||
|
||||
@@ -80,6 +80,7 @@ import {
|
||||
isIncrementalBuildInfo,
|
||||
isIncrementalCompilation,
|
||||
isPackageJsonInfo,
|
||||
isSolutionConfig,
|
||||
loadWithModeAwareCache,
|
||||
maybeBind,
|
||||
missingFileModifiedTime,
|
||||
@@ -1236,7 +1237,13 @@ function getNextInvalidatedProjectCreateInfo<T extends BuilderProgram>(
|
||||
else if (updateLevel === ProgramUpdateLevel.RootNamesAndUpdate) {
|
||||
// Update file names
|
||||
config.fileNames = getFileNamesFromConfigSpecs(config.options.configFile!.configFileSpecs!, getDirectoryPath(project), config.options, state.parseConfigFileHost);
|
||||
updateErrorForNoInputFiles(config.fileNames, project, config.options.configFile!.configFileSpecs!, config.errors, canJsonReportNoInputFiles(config.raw));
|
||||
updateErrorForNoInputFiles(
|
||||
config.fileNames,
|
||||
project,
|
||||
config.options.configFile!.configFileSpecs!,
|
||||
config.errors,
|
||||
canJsonReportNoInputFiles(config.raw),
|
||||
);
|
||||
watchInputFiles(state, project, projectPath, config);
|
||||
watchPackageJsonFiles(state, project, projectPath, config);
|
||||
}
|
||||
@@ -1461,11 +1468,7 @@ function checkConfigFileUpToDateStatus<T extends BuilderProgram>(state: Solution
|
||||
|
||||
function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilderState<T>, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus {
|
||||
// Container if no files are specified in the project
|
||||
if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) {
|
||||
return {
|
||||
type: UpToDateStatusType.ContainerOnly,
|
||||
};
|
||||
}
|
||||
if (isSolutionConfig(project)) return { type: UpToDateStatusType.ContainerOnly };
|
||||
|
||||
// Fast check to see if reference projects are upto date and error free
|
||||
let referenceStatuses;
|
||||
|
||||
@@ -925,7 +925,15 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
|
||||
|
||||
updateLevel = ProgramUpdateLevel.Update;
|
||||
rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions);
|
||||
if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) {
|
||||
if (
|
||||
updateErrorForNoInputFiles(
|
||||
rootFileNames,
|
||||
getNormalizedAbsolutePath(configFileName, currentDirectory),
|
||||
compilerOptions.configFile!.configFileSpecs!,
|
||||
configFileParsingDiagnostics!,
|
||||
canConfigFileJsonReportNoInputFiles,
|
||||
)
|
||||
) {
|
||||
hasChangedConfigFileParsingErrors = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ import { protocol } from "./_namespaces/ts.server.js";
|
||||
|
||||
export interface SessionClientHost extends LanguageServiceHost {
|
||||
writeMessage(message: string): void;
|
||||
openFile(fileName: string): void;
|
||||
}
|
||||
|
||||
interface RenameEntry {
|
||||
@@ -480,6 +481,7 @@ export class SessionClient implements LanguageService {
|
||||
}
|
||||
|
||||
getFileReferences(fileName: string): ReferenceEntry[] {
|
||||
this.host.openFile(fileName);
|
||||
const request = this.processRequest<protocol.FileReferencesRequest>(protocol.CommandTypes.FileReferences, { file: fileName });
|
||||
const response = this.processResponse<protocol.FileReferencesResponse>(request);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ interface ProjectData {
|
||||
projectStateVersion: Project["projectStateVersion"];
|
||||
projectProgramVersion: Project["projectProgramVersion"];
|
||||
dirty: Project["dirty"];
|
||||
initialLoadPending: Project["initialLoadPending"];
|
||||
isClosed: ReturnType<Project["isClosed"]>;
|
||||
isOrphan: ReturnType<Project["isOrphan"]>;
|
||||
noOpenRef: boolean;
|
||||
@@ -123,6 +124,7 @@ export function patchServiceForStateBaseline(service: ProjectService): void {
|
||||
projectDiff = printProperty(PrintPropertyWhen.Always, data, "projectStateVersion", project.projectStateVersion, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.Always, data, "projectProgramVersion", project.projectProgramVersion, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "dirty", project.dirty, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "initialLoadPending", project.initialLoadPending, projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isClosed", project.isClosed(), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "isOrphan", !isBackgroundProject(project) && project.isOrphan(), projectDiff, projectPropertyLogs);
|
||||
projectDiff = printProperty(PrintPropertyWhen.TruthyOrChangedOrNew, data, "noOpenRef", noOpenRef(project), projectDiff, projectPropertyLogs);
|
||||
@@ -154,6 +156,7 @@ export function patchServiceForStateBaseline(service: ProjectService): void {
|
||||
projectStateVersion: project.projectStateVersion,
|
||||
projectProgramVersion: project.projectProgramVersion,
|
||||
dirty: project.dirty,
|
||||
initialLoadPending: project.initialLoadPending,
|
||||
isClosed: project.isClosed(),
|
||||
isOrphan: !isBackgroundProject(project) && project.isOrphan(),
|
||||
noOpenRef: noOpenRef(project),
|
||||
|
||||
+688
-281
File diff suppressed because it is too large
Load Diff
+22
-18
@@ -8,6 +8,7 @@ import {
|
||||
arrayToMap,
|
||||
BuilderState,
|
||||
CachedDirectoryStructureHost,
|
||||
canJsonReportNoInputFiles,
|
||||
canWatchDirectoryOrFilePath,
|
||||
changeExtension,
|
||||
changesAffectModuleResolution,
|
||||
@@ -111,7 +112,6 @@ import {
|
||||
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
|
||||
resolvePackageNameToPackageJson,
|
||||
returnFalse,
|
||||
returnTrue,
|
||||
ScriptKind,
|
||||
some,
|
||||
sortAndDeduplicate,
|
||||
@@ -439,7 +439,8 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
|
||||
protected projectErrors: Diagnostic[] | undefined;
|
||||
|
||||
protected isInitialLoadPending: () => boolean = returnFalse;
|
||||
/** @internal */
|
||||
initialLoadPending = false;
|
||||
|
||||
/** @internal */
|
||||
dirty = false;
|
||||
@@ -1915,7 +1916,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
}
|
||||
|
||||
private filesToStringWorker(writeProjectFileNames: boolean, writeFileExplaination: boolean, writeFileVersionAndText: boolean) {
|
||||
if (this.isInitialLoadPending()) return "\tFiles (0) InitialLoadPending\n";
|
||||
if (this.initialLoadPending) return "\tFiles (0) InitialLoadPending\n";
|
||||
if (!this.program) return "\tFiles (0) NoProgram\n";
|
||||
const sourceFiles = this.program.getSourceFiles();
|
||||
let strBuilder = `\tFiles (${sourceFiles.length})\n`;
|
||||
@@ -1995,7 +1996,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
: (files: Map<string, boolean>) => arrayFrom(files.keys());
|
||||
|
||||
// Update the graph only if initial configured project load is not pending
|
||||
if (!this.isInitialLoadPending()) {
|
||||
if (!this.initialLoadPending) {
|
||||
updateProjectIfDirty(this);
|
||||
}
|
||||
|
||||
@@ -2871,7 +2872,9 @@ export class ConfiguredProject extends Project {
|
||||
openFileWatchTriggered: Map<string, ProgramUpdateLevel> = new Map();
|
||||
|
||||
/** @internal */
|
||||
canConfigFileJsonReportNoInputFiles = false;
|
||||
parsedCommandLine: ParsedCommandLine | undefined;
|
||||
/** @internal */
|
||||
resolvedChildConfigs?: Set<NormalizedPath>;
|
||||
|
||||
private projectReferences: readonly ProjectReference[] | undefined;
|
||||
|
||||
@@ -2886,7 +2889,7 @@ export class ConfiguredProject extends Project {
|
||||
projectOptions?: ProjectOptions | true;
|
||||
|
||||
/** @internal */
|
||||
override isInitialLoadPending: () => boolean = returnTrue;
|
||||
override initialLoadPending = true;
|
||||
|
||||
/** @internal */
|
||||
sendLoadingProjectFinish = false;
|
||||
@@ -2943,7 +2946,7 @@ export class ConfiguredProject extends Project {
|
||||
|
||||
/** @internal */
|
||||
override getParsedCommandLine(fileName: string): ParsedCommandLine | undefined {
|
||||
const configFileName = asNormalizedPath(normalizePath(fileName));
|
||||
const configFileName = toNormalizedPath(fileName);
|
||||
const canonicalConfigFilePath = asNormalizedPath(this.projectService.toCanonicalFileName(configFileName));
|
||||
// Ensure the config file existience info is cached
|
||||
let configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(canonicalConfigFilePath);
|
||||
@@ -2961,7 +2964,7 @@ export class ConfiguredProject extends Project {
|
||||
|
||||
/** @internal */
|
||||
onReleaseParsedCommandLine(fileName: string): void {
|
||||
this.releaseParsedConfig(asNormalizedPath(this.projectService.toCanonicalFileName(asNormalizedPath(normalizePath(fileName)))));
|
||||
this.releaseParsedConfig(asNormalizedPath(this.projectService.toCanonicalFileName(toNormalizedPath(fileName))));
|
||||
}
|
||||
|
||||
private releaseParsedConfig(canonicalConfigFilePath: NormalizedPath) {
|
||||
@@ -2976,7 +2979,7 @@ export class ConfiguredProject extends Project {
|
||||
override updateGraph(): boolean {
|
||||
if (this.deferredClose) return false;
|
||||
const isDirty = this.dirty;
|
||||
this.isInitialLoadPending = returnFalse;
|
||||
this.initialLoadPending = false;
|
||||
const updateLevel = this.pendingUpdateLevel;
|
||||
this.pendingUpdateLevel = ProgramUpdateLevel.Update;
|
||||
let result: boolean;
|
||||
@@ -3036,7 +3039,7 @@ export class ConfiguredProject extends Project {
|
||||
|
||||
/** @internal */
|
||||
setPotentialProjectReference(canonicalConfigPath: NormalizedPath): void {
|
||||
Debug.assert(this.isInitialLoadPending());
|
||||
Debug.assert(this.initialLoadPending);
|
||||
(this.potentialProjectReferences || (this.potentialProjectReferences = new Set())).add(canonicalConfigPath);
|
||||
}
|
||||
|
||||
@@ -3112,12 +3115,6 @@ export class ConfiguredProject extends Project {
|
||||
super.markAsDirty();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
isSolution(): boolean {
|
||||
return this.getRootFilesMap().size === 0 &&
|
||||
!this.canConfigFileJsonReportNoInputFiles;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
override isOrphan(): boolean {
|
||||
return !!this.deferredClose;
|
||||
@@ -3128,8 +3125,15 @@ export class ConfiguredProject extends Project {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
updateErrorOnNoInputFiles(fileNames: string[]): void {
|
||||
updateErrorForNoInputFiles(fileNames, this.getConfigFilePath(), this.getCompilerOptions().configFile!.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles);
|
||||
updateErrorOnNoInputFiles(parsedCommandLine: ParsedCommandLine): void {
|
||||
this.parsedCommandLine = parsedCommandLine;
|
||||
updateErrorForNoInputFiles(
|
||||
parsedCommandLine.fileNames,
|
||||
this.getConfigFilePath(),
|
||||
this.getCompilerOptions().configFile!.configFileSpecs!,
|
||||
this.projectErrors!,
|
||||
canJsonReportNoInputFiles(parsedCommandLine.raw),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -498,6 +498,10 @@ export interface ProjectInfoRequestArgs extends FileRequestArgs {
|
||||
* Indicate if the file name list of the project is needed
|
||||
*/
|
||||
needFileNameList: boolean;
|
||||
/**
|
||||
* if true returns details about default configured project calculation
|
||||
*/
|
||||
needDefaultConfiguredProjectInfo?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,6 +529,18 @@ export interface CompilerOptionsDiagnosticsRequestArgs {
|
||||
projectFileName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Details about the default project for the file if tsconfig file is found
|
||||
*/
|
||||
export interface DefaultConfiguredProjectInfo {
|
||||
/** List of config files looked and did not match because file was not part of root file names */
|
||||
notMatchedByConfig?: readonly string[];
|
||||
/** List of projects which were loaded but file was not part of the project or is file from referenced project */
|
||||
notInProject?: readonly string[];
|
||||
/** Configured project used as default */
|
||||
defaultProject?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Response message body for "projectInfo" request
|
||||
*/
|
||||
@@ -542,6 +558,10 @@ export interface ProjectInfo {
|
||||
* Indicates if the project has a active language service instance
|
||||
*/
|
||||
languageServiceDisabled?: boolean;
|
||||
/**
|
||||
* Information about default project
|
||||
*/
|
||||
configuredProjectInfo?: DefaultConfiguredProjectInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -688,14 +688,6 @@ export class ScriptInfo {
|
||||
return this.deferredDelete || !forEach(this.containingProjects, p => !p.isOrphan());
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
isContainedByBackgroundProject(): boolean {
|
||||
return some(
|
||||
this.containingProjects,
|
||||
isBackgroundProject,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1 based index
|
||||
*/
|
||||
@@ -746,3 +738,19 @@ function failIfInvalidLocation(location: protocol.Location) {
|
||||
Debug.assert(location.line > 0, `Expected line to be non-${location.line === 0 ? "zero" : "negative"}`);
|
||||
Debug.assert(location.offset > 0, `Expected offset to be non-${location.offset === 0 ? "zero" : "negative"}`);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function scriptInfoIsContainedByBackgroundProject(info: ScriptInfo): boolean {
|
||||
return some(
|
||||
info.containingProjects,
|
||||
isBackgroundProject,
|
||||
);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function scriptInfoIsContainedByDeferredClosedProject(info: ScriptInfo): boolean {
|
||||
return some(
|
||||
info.containingProjects,
|
||||
isProjectDeferredClose,
|
||||
);
|
||||
}
|
||||
|
||||
+108
-33
@@ -143,6 +143,7 @@ import {
|
||||
CloseFileWatcherEvent,
|
||||
ConfigFileDiagEvent,
|
||||
ConfiguredProject,
|
||||
ConfiguredProjectLoadKind,
|
||||
convertFormatOptions,
|
||||
convertScriptKindName,
|
||||
convertUserPreferences,
|
||||
@@ -524,7 +525,8 @@ function getRenameLocationsWorker(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
/*isForRename*/ true,
|
||||
getDefinitionLocation(defaultProject, initialLocation, /*isForRename*/ true),
|
||||
mapDefinitionInProject,
|
||||
(project, position) => project.getLanguageService().findRenameLocations(position.fileName, position.pos, findInStrings, findInComments, preferences),
|
||||
(renameLocation, cb) => cb(documentSpanLocation(renameLocation)),
|
||||
);
|
||||
@@ -569,7 +571,8 @@ function getReferencesWorker(
|
||||
projects,
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
/*isForRename*/ false,
|
||||
getDefinitionLocation(defaultProject, initialLocation, /*isForRename*/ false),
|
||||
mapDefinitionInProject,
|
||||
(project, position) => {
|
||||
logger.info(`Finding references to ${position.fileName} position ${position.pos} in project ${project.getProjectName()}`);
|
||||
return project.getLanguageService().findReferences(position.fileName, position.pos);
|
||||
@@ -709,9 +712,15 @@ function getPerProjectReferences<TResult>(
|
||||
projects: Projects,
|
||||
defaultProject: Project,
|
||||
initialLocation: DocumentPosition,
|
||||
isForRename: boolean,
|
||||
defaultDefinition: DocumentPosition | undefined,
|
||||
mapDefinitionInProject: (
|
||||
definition: DocumentPosition,
|
||||
project: Project,
|
||||
getGeneratedDefinition: () => DocumentPosition | undefined,
|
||||
getSourceDefinition: () => DocumentPosition | undefined,
|
||||
) => DocumentPosition | undefined,
|
||||
getResultsForPosition: (project: Project, location: DocumentPosition) => readonly TResult[] | undefined,
|
||||
forPositionInResult: (result: TResult, cb: (location: DocumentPosition) => void) => void,
|
||||
forPositionInResult?: (result: TResult, cb: (location: DocumentPosition) => void) => void,
|
||||
): readonly TResult[] | Map<Project, readonly TResult[]> {
|
||||
// If `getResultsForPosition` returns results for a project, they go in here
|
||||
const resultsMap = new Map<Project, readonly TResult[]>();
|
||||
@@ -733,8 +742,6 @@ function getPerProjectReferences<TResult>(
|
||||
const projectService = defaultProject.projectService;
|
||||
const cancellationToken = defaultProject.getCancellationToken();
|
||||
|
||||
const defaultDefinition = getDefinitionLocation(defaultProject, initialLocation, isForRename);
|
||||
|
||||
// Don't call these unless !!defaultDefinition
|
||||
const getGeneratedDefinition = memoize(() =>
|
||||
defaultProject.isSourceOfProjectReferenceRedirect(defaultDefinition!.fileName) ?
|
||||
@@ -800,7 +807,7 @@ function getPerProjectReferences<TResult>(
|
||||
|
||||
function searchPosition(project: Project, location: DocumentPosition): readonly TResult[] | undefined {
|
||||
const projectResults = getResultsForPosition(project, location);
|
||||
if (!projectResults) return undefined;
|
||||
if (!projectResults || !forPositionInResult) return projectResults;
|
||||
|
||||
for (const result of projectResults) {
|
||||
forPositionInResult(result, position => {
|
||||
@@ -833,12 +840,10 @@ function getPerProjectReferences<TResult>(
|
||||
}
|
||||
}
|
||||
|
||||
function mapDefinitionInProject(
|
||||
function mapDefinitionInProjectIfFileInProject(
|
||||
definition: DocumentPosition,
|
||||
project: Project,
|
||||
getGeneratedDefinition: () => DocumentPosition | undefined,
|
||||
getSourceDefinition: () => DocumentPosition | undefined,
|
||||
): DocumentPosition | undefined {
|
||||
) {
|
||||
// If the definition is actually from the project, definition is correct as is
|
||||
if (
|
||||
project.containsFile(toNormalizedPath(definition.fileName)) &&
|
||||
@@ -846,13 +851,24 @@ function mapDefinitionInProject(
|
||||
) {
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
|
||||
function mapDefinitionInProject(
|
||||
definition: DocumentPosition,
|
||||
project: Project,
|
||||
getGeneratedDefinition: () => DocumentPosition | undefined,
|
||||
getSourceDefinition: () => DocumentPosition | undefined,
|
||||
): DocumentPosition | undefined {
|
||||
// If the definition is actually from the project, definition is correct as is
|
||||
const result = mapDefinitionInProjectIfFileInProject(definition, project);
|
||||
if (result) return result;
|
||||
const generatedDefinition = getGeneratedDefinition();
|
||||
if (generatedDefinition && project.containsFile(toNormalizedPath(generatedDefinition.fileName))) return generatedDefinition;
|
||||
const sourceDefinition = getSourceDefinition();
|
||||
return sourceDefinition && project.containsFile(toNormalizedPath(sourceDefinition.fileName)) ? sourceDefinition : undefined;
|
||||
}
|
||||
|
||||
function isLocationProjectReferenceRedirect(project: Project, location: DocumentPosition | undefined) {
|
||||
function isLocationProjectReferenceRedirect(project: Project, location: Pick<DocumentPosition, "fileName"> | undefined) {
|
||||
if (!location) return false;
|
||||
const program = project.getLanguageService().getProgram();
|
||||
if (!program) return false;
|
||||
@@ -2039,20 +2055,63 @@ export class Session<TMessage = string> implements EventSender {
|
||||
}
|
||||
|
||||
private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo {
|
||||
return this.getProjectInfoWorker(args.file, args.projectFileName, args.needFileNameList, /*excludeConfigFiles*/ false);
|
||||
return this.getProjectInfoWorker(
|
||||
args.file,
|
||||
args.projectFileName,
|
||||
args.needFileNameList,
|
||||
args.needDefaultConfiguredProjectInfo,
|
||||
/*excludeConfigFiles*/ false,
|
||||
);
|
||||
}
|
||||
|
||||
private getProjectInfoWorker(uncheckedFileName: string, projectFileName: string | undefined, needFileNameList: boolean, excludeConfigFiles: boolean) {
|
||||
private getProjectInfoWorker(
|
||||
uncheckedFileName: string,
|
||||
projectFileName: string | undefined,
|
||||
needFileNameList: boolean,
|
||||
needDefaultConfiguredProjectInfo: boolean | undefined,
|
||||
excludeConfigFiles: boolean,
|
||||
): Omit<protocol.ProjectInfo, "fileNames"> & { fileNames?: NormalizedPath[]; } {
|
||||
const { project } = this.getFileAndProjectWorker(uncheckedFileName, projectFileName);
|
||||
updateProjectIfDirty(project);
|
||||
const projectInfo = {
|
||||
configFileName: project.getProjectName(),
|
||||
languageServiceDisabled: !project.languageServiceEnabled,
|
||||
fileNames: needFileNameList ? project.getFileNames(/*excludeFilesFromExternalLibraries*/ false, excludeConfigFiles) : undefined,
|
||||
configuredProjectInfo: needDefaultConfiguredProjectInfo ? this.getDefaultConfiguredProjectInfo(uncheckedFileName) : undefined,
|
||||
};
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
private getDefaultConfiguredProjectInfo(uncheckedFileName: string): protocol.DefaultConfiguredProjectInfo | undefined {
|
||||
const info = this.projectService.getScriptInfo(uncheckedFileName);
|
||||
if (!info) return;
|
||||
|
||||
// Find default project for the info
|
||||
const result = this.projectService.findDefaultConfiguredProjectWorker(
|
||||
info,
|
||||
ConfiguredProjectLoadKind.CreateReplay,
|
||||
);
|
||||
if (!result) return undefined;
|
||||
let notMatchedByConfig: NormalizedPath[] | undefined;
|
||||
let notInProject: NormalizedPath[] | undefined;
|
||||
result.seenProjects.forEach((kind, project) => {
|
||||
if (project !== result.defaultProject) {
|
||||
if (kind !== ConfiguredProjectLoadKind.CreateReplay) {
|
||||
(notMatchedByConfig ??= []).push(toNormalizedPath(project.getConfigFilePath()));
|
||||
}
|
||||
else {
|
||||
(notInProject ??= []).push(toNormalizedPath(project.getConfigFilePath()));
|
||||
}
|
||||
}
|
||||
});
|
||||
result.seenConfigs?.forEach(config => (notMatchedByConfig ??= []).push(config));
|
||||
return {
|
||||
notMatchedByConfig,
|
||||
notInProject,
|
||||
defaultProject: result.defaultProject && toNormalizedPath(result.defaultProject.getConfigFilePath()),
|
||||
};
|
||||
}
|
||||
|
||||
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
@@ -2187,25 +2246,38 @@ export class Session<TMessage = string> implements EventSender {
|
||||
|
||||
private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] {
|
||||
const projects = this.getProjects(args);
|
||||
const fileName = args.file;
|
||||
const preferences = this.getPreferences(toNormalizedPath(fileName));
|
||||
const fileName = toNormalizedPath(args.file);
|
||||
const preferences = this.getPreferences(fileName);
|
||||
const initialLocation: DocumentPosition = { fileName, pos: 0 };
|
||||
const perProjectResults = getPerProjectReferences(
|
||||
projects,
|
||||
this.getDefaultProject(args),
|
||||
initialLocation,
|
||||
initialLocation,
|
||||
mapDefinitionInProjectIfFileInProject,
|
||||
project => {
|
||||
this.logger.info(`Finding references to file ${fileName} in project ${project.getProjectName()}`);
|
||||
return project.getLanguageService().getFileReferences(fileName);
|
||||
},
|
||||
);
|
||||
|
||||
const references: ReferenceEntry[] = [];
|
||||
const seen = createDocumentSpanSet(this.host.useCaseSensitiveFileNames);
|
||||
|
||||
forEachProjectInProjects(projects, /*path*/ undefined, project => {
|
||||
if (project.getCancellationToken().isCancellationRequested()) return;
|
||||
|
||||
const projectOutputs = project.getLanguageService().getFileReferences(fileName);
|
||||
if (projectOutputs) {
|
||||
// No re-mapping or isDefinition updatses are required if there's exactly one project
|
||||
let references: ReferenceEntry[];
|
||||
if (isArray(perProjectResults)) {
|
||||
references = perProjectResults as ReferenceEntry[];
|
||||
}
|
||||
else {
|
||||
references = [];
|
||||
const seen = createDocumentSpanSet(this.host.useCaseSensitiveFileNames);
|
||||
perProjectResults.forEach(projectOutputs => {
|
||||
for (const referenceEntry of projectOutputs) {
|
||||
if (!seen.has(referenceEntry)) {
|
||||
references.push(referenceEntry);
|
||||
seen.add(referenceEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!simplifiedResult) return references;
|
||||
const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences));
|
||||
@@ -3091,16 +3163,19 @@ export class Session<TMessage = string> implements EventSender {
|
||||
return;
|
||||
}
|
||||
|
||||
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(fileName, /*projectFileName*/ undefined, /*needFileNameList*/ true, /*excludeConfigFiles*/ true);
|
||||
if (languageServiceDisabled) {
|
||||
return;
|
||||
}
|
||||
const { fileNames, languageServiceDisabled } = this.getProjectInfoWorker(
|
||||
fileName,
|
||||
/*projectFileName*/ undefined,
|
||||
/*needFileNameList*/ true,
|
||||
/*needDefaultConfiguredProjectInfo*/ undefined,
|
||||
/*excludeConfigFiles*/ true,
|
||||
);
|
||||
|
||||
if (languageServiceDisabled) return;
|
||||
|
||||
// No need to analyze lib.d.ts
|
||||
const fileNamesInProject = fileNames!.filter(value => !value.includes("lib.d.ts")); // TODO: GH#18217
|
||||
if (fileNamesInProject.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (fileNamesInProject.length === 0) return;
|
||||
|
||||
// Sort the file name list to make the recently touched files come first
|
||||
const highPriorityFiles: NormalizedPath[] = [];
|
||||
|
||||
@@ -462,6 +462,20 @@ export function openFilesForSession(
|
||||
}
|
||||
}
|
||||
|
||||
export function projectInfoForSession(
|
||||
session: TestSession,
|
||||
file: string | File,
|
||||
) {
|
||||
return session.executeCommandSeq<ts.server.protocol.ProjectInfoRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ProjectInfo,
|
||||
arguments: {
|
||||
file: ts.isString(file) ? file : file.path,
|
||||
needFileNameList: false,
|
||||
needDefaultConfiguredProjectInfo: true,
|
||||
},
|
||||
}).response as ts.server.protocol.ProjectInfo;
|
||||
}
|
||||
|
||||
export function closeFilesForSession(files: readonly (File | string)[], session: TestSession): void {
|
||||
for (const file of files) {
|
||||
session.executeCommandSeq<ts.server.protocol.CloseRequest>({
|
||||
|
||||
@@ -46,7 +46,7 @@ describe("unittests:: tsserver:: auxiliaryProject::", () => {
|
||||
// project should throw.
|
||||
const bJsScriptInfo = ts.Debug.checkDefined(session.getProjectService().getScriptInfo(bJs.path));
|
||||
assert(bJsScriptInfo.isOrphan());
|
||||
assert(bJsScriptInfo.isContainedByBackgroundProject());
|
||||
assert(ts.server.scriptInfoIsContainedByBackgroundProject(bJsScriptInfo));
|
||||
assert.deepEqual(bJsScriptInfo.containingProjects, [auxProject]);
|
||||
assert.throws(() => bJsScriptInfo.getDefaultProject());
|
||||
|
||||
@@ -54,7 +54,7 @@ describe("unittests:: tsserver:: auxiliaryProject::", () => {
|
||||
// even though it's still contained by the AuxiliaryProject.
|
||||
openFilesForSession([bJs], session);
|
||||
assert(!bJsScriptInfo.isOrphan());
|
||||
assert(bJsScriptInfo.isContainedByBackgroundProject());
|
||||
assert(ts.server.scriptInfoIsContainedByBackgroundProject(bJsScriptInfo));
|
||||
assert.equal(bJsScriptInfo.getDefaultProject().projectKind, ts.server.ProjectKind.Inferred);
|
||||
baselineTsserverLogs("auxiliaryProject", "does not remove scrips from InferredProject", session);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as ts from "../../_namespaces/ts.js";
|
||||
import { jsonToReadableText } from "../helpers.js";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
projectInfoForSession,
|
||||
TestSession,
|
||||
TestSessionRequest,
|
||||
} from "../helpers/tsserver.js";
|
||||
@@ -88,10 +89,7 @@ describe("unittests:: tsserver:: cancellationToken::", () => {
|
||||
});
|
||||
|
||||
// run new request
|
||||
session.executeCommandSeq<ts.server.protocol.ProjectInfoRequest>({
|
||||
command: ts.server.protocol.CommandTypes.ProjectInfo,
|
||||
arguments: { file: f1.path, needFileNameList: false },
|
||||
});
|
||||
projectInfoForSession(session, f1);
|
||||
|
||||
// cancel previously issued Geterr
|
||||
session.serverCancellationToken.setRequestToCancel(getErrId);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
baselineTsserverLogs,
|
||||
closeFilesForSession,
|
||||
openFilesForSession,
|
||||
projectInfoForSession,
|
||||
TestSession,
|
||||
verifyGetErrRequest,
|
||||
} from "../helpers/tsserver.js";
|
||||
@@ -152,6 +153,7 @@ describe("unittests:: tsserver:: configuredProjects::", () => {
|
||||
const { host, session, commonFile1, commonFile2, configFile } = setup(parentOrSiblingConfigFile);
|
||||
|
||||
openFilesForSession([commonFile1], session);
|
||||
projectInfoForSession(session, commonFile1);
|
||||
|
||||
session.logger.log("1: When config file is deleted and then another file is opened");
|
||||
// remove the tsconfig file
|
||||
@@ -236,6 +238,27 @@ describe("unittests:: tsserver:: configuredProjects::", () => {
|
||||
openFilesForSession([commonFile1, commonFile2], session);
|
||||
closeFilesForSession([commonFile2], session);
|
||||
openFilesForSession([{ file: "/user/username/projects/random/random.ts", content: "export const y = 10;" }], session);
|
||||
closeFilesForSession(["/user/username/projects/random/random.ts"], session);
|
||||
|
||||
session.logger.log("7: When config file is deleted and then another file is opened and projectInfo");
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
projectInfoForSession(session, commonFile1);
|
||||
projectInfoForSession(session, commonFile2);
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
session.logger.log("8: When both files are open and config file is deleted and projectInfo");
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
projectInfoForSession(session, commonFile1);
|
||||
projectInfoForSession(session, commonFile2);
|
||||
|
||||
baselineTsserverLogs("configuredProjects", `add and then remove a config file ${scenario}`, session);
|
||||
});
|
||||
@@ -243,6 +266,7 @@ describe("unittests:: tsserver:: configuredProjects::", () => {
|
||||
it(`add and then remove a config file ${scenario} and file from first config is not open`, () => {
|
||||
const { host, session, commonFile2, configFile } = setup(parentOrSiblingConfigFile);
|
||||
openFilesForSession([commonFile2], session);
|
||||
projectInfoForSession(session, commonFile2);
|
||||
|
||||
session.logger.log("1: When config file is deleted");
|
||||
// remove the tsconfig file
|
||||
@@ -271,6 +295,27 @@ describe("unittests:: tsserver:: configuredProjects::", () => {
|
||||
closeFilesForSession([commonFile2], session);
|
||||
openFilesForSession([{ file: "/user/username/projects/random/random.ts", content: "export const y = 10;" }], session);
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
closeFilesForSession(["/user/username/projects/random/random.ts"], session);
|
||||
openFilesForSession([commonFile2], session);
|
||||
|
||||
session.logger.log("3: When config file is deleted and projectInfo");
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
projectInfoForSession(session, commonFile2);
|
||||
|
||||
// Add a tsconfig file
|
||||
host.writeFile(configFile.path, configFile.content);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
session.logger.log("4: Check when file is closed when config file is deleted and projectInfo");
|
||||
// remove the tsconfig file
|
||||
host.deleteFile(configFile.path);
|
||||
projectInfoForSession(session, commonFile2);
|
||||
|
||||
baselineTsserverLogs("configuredProjects", `add and then remove a config file ${scenario} and file from first config is not open`, session);
|
||||
});
|
||||
}
|
||||
@@ -995,7 +1040,7 @@ foo();`,
|
||||
endOffset: 1,
|
||||
},
|
||||
});
|
||||
session.logger.log(`Default project for file: ${fooDts}: ${session.getProjectService().tryGetDefaultProjectForFile(ts.server.toNormalizedPath(fooDts))?.projectName}`);
|
||||
projectInfoForSession(session, fooDts);
|
||||
baselineTsserverLogs("configuredProjects", "when default configured project does not contain the file", session);
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
closeFilesForSession,
|
||||
createHostWithSolutionBuild,
|
||||
openFilesForSession,
|
||||
projectInfoForSession,
|
||||
protocolFileLocationFromSubstring,
|
||||
protocolLocationFromSubstring,
|
||||
TestSession,
|
||||
@@ -20,10 +21,10 @@ import {
|
||||
|
||||
function logDefaultProjectAndDefaultConfiguredProject(session: TestSession, file: File) {
|
||||
const info = session.getProjectService().getScriptInfo(file.path);
|
||||
const defaultProject = session.getProjectService().tryGetDefaultProjectForFile(file.path as ts.server.NormalizedPath);
|
||||
const defaultConfiguredProject = info && session.getProjectService().findDefaultConfiguredProject(info);
|
||||
session.logger.info(`File: ${file.path}:\n\tgetDefaultProjectForFile:\n\t\t${defaultProject?.projectName}\n\tfindDefaultConfiguredProject:\n\t\t${defaultConfiguredProject?.projectName}`);
|
||||
return { defaultProject, defaultConfiguredProject };
|
||||
if (info) {
|
||||
const projectInfo = projectInfoForSession(session, file);
|
||||
return session.getProjectService().findProject(projectInfo.configFileName);
|
||||
}
|
||||
}
|
||||
|
||||
describe("unittests:: tsserver:: with projectReferences:: and tsbuild", () => {
|
||||
@@ -581,7 +582,7 @@ testCompositeFunction('why hello there', 42);`,
|
||||
baselineTsserverLogs("projectReferences", `when the referenced projects have allowJs and emitDeclarationOnly`, session);
|
||||
});
|
||||
|
||||
it("when finding local reference doesnt load ancestor/sibling projects", () => {
|
||||
it("when finding local reference doesnt load ancestor sibling projects", () => {
|
||||
const solutionLocation = "/user/username/projects/solution";
|
||||
const solution: File = {
|
||||
path: `${solutionLocation}/tsconfig.json`,
|
||||
@@ -661,7 +662,7 @@ testCompositeFunction('why hello there', 42);`,
|
||||
command: ts.server.protocol.CommandTypes.References,
|
||||
arguments: protocolFileLocationFromSubstring(programFile, "getSourceFiles"),
|
||||
});
|
||||
baselineTsserverLogs("projectReferences", `finding local reference doesnt load ancestor/sibling projects`, session);
|
||||
baselineTsserverLogs("projectReferences", "finding local reference doesnt load ancestor sibling projects", session);
|
||||
});
|
||||
|
||||
it("when finding references in overlapping projects", () => {
|
||||
@@ -1080,7 +1081,7 @@ export function bar() {}`,
|
||||
|
||||
function verifySolutionScenario(input: Setup) {
|
||||
const { session, host } = setup(input);
|
||||
const { defaultProject } = logDefaultProjectAndDefaultConfiguredProject(session, main);
|
||||
const defaultProject = logDefaultProjectAndDefaultConfiguredProject(session, main);
|
||||
|
||||
// Verify errors
|
||||
verifyGetErrRequest({ session, files: [main] });
|
||||
|
||||
Reference in New Issue
Block a user