Add error related to file not in rootDir and file not part of included root files at the references
This commit is contained in:
parent
fd515b519e
commit
8ac45805c0
|
@ -552,6 +552,12 @@ namespace ts {
|
|||
allDiagnostics?: Diagnostic[];
|
||||
}
|
||||
|
||||
interface RefFile extends TextRange {
|
||||
kind: RefFileKind;
|
||||
index: number;
|
||||
file: SourceFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if program structure is upto date or needs to be recreated
|
||||
*/
|
||||
|
@ -717,6 +723,8 @@ namespace ts {
|
|||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
let classifiableNames: UnderscoreEscapedMap<true>;
|
||||
const ambientModuleNameToUnmodifiedFileName = createMap<string>();
|
||||
// Todo:: Use this to report why file was included in --extendedDiagnostics
|
||||
let refFileMap: MultiMap<ts.RefFile> | undefined;
|
||||
|
||||
const cachedSemanticDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
|
||||
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
|
||||
|
@ -913,6 +921,7 @@ namespace ts {
|
|||
getSourceFileByPath,
|
||||
getSourceFiles: () => files,
|
||||
getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
|
||||
getRefFileMap: () => refFileMap,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
getOptionsDiagnostics,
|
||||
|
@ -1391,6 +1400,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
missingFilePaths = oldProgram.getMissingFilePaths();
|
||||
refFileMap = oldProgram.getRefFileMap();
|
||||
|
||||
// update fileName -> file mapping
|
||||
for (const newSourceFile of newSourceFiles) {
|
||||
|
@ -2179,25 +2189,24 @@ namespace ts {
|
|||
}
|
||||
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
: createCompilerDiagnostic(diagnostic, ...args));
|
||||
},
|
||||
refFile);
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: RefFile): void {
|
||||
getSourceFileFromReferenceWorker(
|
||||
fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => fileProcessingDiagnostics.add(
|
||||
createRefFileDiagnostic(refFile, diagnostic, ...args)
|
||||
),
|
||||
refFile && refFile.file
|
||||
);
|
||||
}
|
||||
|
||||
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: SourceFile, refPos: number, refEnd: number): void {
|
||||
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, existingFileName));
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, existingFileName));
|
||||
}
|
||||
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: RefFile | undefined): void {
|
||||
fileProcessingDiagnostics.add(createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
|
||||
fileName,
|
||||
existingFileName
|
||||
));
|
||||
}
|
||||
|
||||
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string): SourceFile {
|
||||
|
@ -2222,7 +2231,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
const originalFileName = fileName;
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
|
@ -2239,7 +2248,7 @@ namespace ts {
|
|||
const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
|
||||
const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(inputName, currentDirectory);
|
||||
if (checkedAbsolutePath !== inputAbsolutePath) {
|
||||
reportFileNamesDifferOnlyInCasingError(inputName, checkedName, refFile, refPos, refEnd);
|
||||
reportFileNamesDifferOnlyInCasingError(inputName, checkedName, refFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2266,6 +2275,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
addFileToRefFileMap(file || undefined, refFile);
|
||||
return file || undefined;
|
||||
}
|
||||
|
||||
|
@ -2289,15 +2299,17 @@ namespace ts {
|
|||
}
|
||||
|
||||
// We haven't looked for this file, do so now and cache result
|
||||
const file = host.getSourceFile(fileName, options.target!, hostErrorMessage => { // TODO: GH#18217
|
||||
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
|
||||
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
|
||||
}
|
||||
}, shouldCreateNewSourceFile);
|
||||
const file = host.getSourceFile(
|
||||
fileName,
|
||||
options.target!,
|
||||
hostErrorMessage => fileProcessingDiagnostics.add(createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Cannot_read_file_0_Colon_1,
|
||||
fileName,
|
||||
hostErrorMessage
|
||||
)),
|
||||
shouldCreateNewSourceFile
|
||||
);
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = packageIdToString(packageId);
|
||||
|
@ -2331,7 +2343,7 @@ namespace ts {
|
|||
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
|
||||
const existingFile = filesByNameIgnoreCase!.get(pathLowerCase);
|
||||
if (existingFile) {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile);
|
||||
}
|
||||
else {
|
||||
filesByNameIgnoreCase!.set(pathLowerCase, file);
|
||||
|
@ -2359,10 +2371,20 @@ namespace ts {
|
|||
processingOtherFiles!.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
addFileToRefFileMap(file, refFile);
|
||||
return file;
|
||||
}
|
||||
|
||||
function addFileToRefFileMap(file: SourceFile | undefined, refFile: RefFile | undefined) {
|
||||
if (refFile && file) {
|
||||
(refFileMap || (refFileMap = createMultiMap())).add(file.path, {
|
||||
kind: refFile.kind,
|
||||
index: refFile.index,
|
||||
file: refFile.file.path
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
|
||||
if (redirectedPath) {
|
||||
filesByName.set(redirectedPath, file);
|
||||
|
@ -2479,9 +2501,21 @@ namespace ts {
|
|||
}
|
||||
|
||||
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
|
||||
forEach(file.referencedFiles, ref => {
|
||||
forEach(file.referencedFiles, (ref, index) => {
|
||||
const referencedFileName = resolveTripleslashReference(ref.fileName, file.originalFileName);
|
||||
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
|
||||
processSourceFile(
|
||||
referencedFileName,
|
||||
isDefaultLib,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
/*packageId*/ undefined,
|
||||
{
|
||||
kind: RefFileKind.ReferenceFile,
|
||||
index,
|
||||
file,
|
||||
pos: ref.pos,
|
||||
end: ref.end
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2500,12 +2534,25 @@ namespace ts {
|
|||
// store resolved type directive on the file
|
||||
const fileName = ref.fileName.toLocaleLowerCase();
|
||||
setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
|
||||
processTypeReferenceDirective(fileName, resolvedTypeReferenceDirective, file, ref.pos, ref.end);
|
||||
processTypeReferenceDirective(
|
||||
fileName,
|
||||
resolvedTypeReferenceDirective,
|
||||
{
|
||||
kind: RefFileKind.TypeReferenceDirective,
|
||||
index: i,
|
||||
file,
|
||||
pos: ref.pos,
|
||||
end: ref.end
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function processTypeReferenceDirective(typeReferenceDirective: string, resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
|
||||
refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
function processTypeReferenceDirective(
|
||||
typeReferenceDirective: string,
|
||||
resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
|
||||
refFile?: RefFile
|
||||
): void {
|
||||
|
||||
// If we already found this library as a primary reference - nothing to do
|
||||
const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective);
|
||||
|
@ -2518,7 +2565,7 @@ namespace ts {
|
|||
|
||||
if (resolvedTypeReferenceDirective.primary) {
|
||||
// resolved from the primary path
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// If we already resolved to this file, it must have been a secondary reference. Check file contents
|
||||
|
@ -2528,12 +2575,15 @@ namespace ts {
|
|||
if (resolvedTypeReferenceDirective.resolvedFileName !== previousResolution.resolvedFileName) {
|
||||
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName!);
|
||||
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName!)!.text) {
|
||||
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, // TODO: GH#18217
|
||||
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
|
||||
typeReferenceDirective,
|
||||
resolvedTypeReferenceDirective.resolvedFileName,
|
||||
previousResolution.resolvedFileName
|
||||
));
|
||||
fileProcessingDiagnostics.add(
|
||||
createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
|
||||
typeReferenceDirective,
|
||||
resolvedTypeReferenceDirective.resolvedFileName,
|
||||
previousResolution.resolvedFileName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
// don't overwrite previous resolution result
|
||||
|
@ -2541,14 +2591,18 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
// First resolution of this library
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
|
||||
}
|
||||
else {
|
||||
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, Diagnostics.Cannot_find_type_definition_file_for_0, typeReferenceDirective)); // TODO: GH#18217
|
||||
fileProcessingDiagnostics.add(createRefFileDiagnostic(
|
||||
refFile,
|
||||
Diagnostics.Cannot_find_type_definition_file_for_0,
|
||||
typeReferenceDirective
|
||||
));
|
||||
}
|
||||
|
||||
if (saveResolution) {
|
||||
|
@ -2568,17 +2622,24 @@ namespace ts {
|
|||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
|
||||
fileProcessingDiagnostics.add(createDiagnostic(file, libReference.pos, libReference.end, message, libName, suggestion));
|
||||
fileProcessingDiagnostics.add(createFileDiagnostic(
|
||||
file,
|
||||
libReference.pos,
|
||||
libReference.end - libReference.pos,
|
||||
message,
|
||||
libName,
|
||||
suggestion
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
|
||||
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
|
||||
function createRefFileDiagnostic(refFile: RefFile | undefined, message: DiagnosticMessage, ...args: any[]): Diagnostic {
|
||||
if (!refFile) {
|
||||
return createCompilerDiagnostic(message, ...args);
|
||||
}
|
||||
else {
|
||||
return createFileDiagnostic(refFile, refPos, refEnd - refPos, message, ...args);
|
||||
return createFileDiagnostic(refFile.file, refFile.pos, refFile.end - refFile.pos, message, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2632,7 +2693,20 @@ namespace ts {
|
|||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
findSourceFile(
|
||||
resolvedFileName,
|
||||
path,
|
||||
/*isDefaultLib*/ false,
|
||||
/*ignoreNoDefaultLib*/ false,
|
||||
{
|
||||
kind: RefFileKind.Import,
|
||||
index: i,
|
||||
file,
|
||||
pos,
|
||||
end: file.imports[i].end
|
||||
},
|
||||
resolution.packageId
|
||||
);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
|
@ -2654,12 +2728,20 @@ namespace ts {
|
|||
function checkSourceFilesBelongToPath(sourceFiles: ReadonlyArray<SourceFile>, rootDirectory: string): boolean {
|
||||
let allFilesBelongToPath = true;
|
||||
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
|
||||
let rootPaths: Map<true> | undefined;
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (!sourceFile.isDeclarationFile) {
|
||||
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
|
||||
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
|
||||
if (!rootPaths) rootPaths = arrayToSet(rootNames, toPath);
|
||||
addProgramDiagnosticAtRefPath(
|
||||
sourceFile,
|
||||
rootPaths,
|
||||
Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
|
||||
sourceFile.fileName,
|
||||
rootDirectory
|
||||
);
|
||||
allFilesBelongToPath = false;
|
||||
}
|
||||
}
|
||||
|
@ -2771,12 +2853,18 @@ namespace ts {
|
|||
|
||||
// List of collected files is complete; validate exhautiveness if this is a project with a file list
|
||||
if (options.composite) {
|
||||
const rootPaths = rootNames.map(toPath);
|
||||
const rootPaths = arrayToSet(rootNames, toPath);
|
||||
for (const file of files) {
|
||||
// Ignore file that is not emitted
|
||||
if (!sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)) continue;
|
||||
if (rootPaths.indexOf(file.path) === -1) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, file.fileName, options.configFilePath || ""));
|
||||
if (!rootPaths.has(file.path)) {
|
||||
addProgramDiagnosticAtRefPath(
|
||||
file,
|
||||
rootPaths,
|
||||
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
|
||||
file.fileName,
|
||||
options.configFilePath || ""
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2984,6 +3072,35 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function addProgramDiagnosticAtRefPath(file: SourceFile, rootPaths: Map<true>, message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
|
||||
const refPaths = refFileMap && refFileMap.get(file.path);
|
||||
const refPathToReportErrorOn = forEach(refPaths, refPath => rootPaths.has(refPath.file) ? refPath : undefined) ||
|
||||
elementAt(refPaths, 0);
|
||||
if (refPathToReportErrorOn) {
|
||||
const refFile = Debug.assertDefined(getSourceFileByPath(refPathToReportErrorOn.file));
|
||||
const { kind, index } = refPathToReportErrorOn;
|
||||
let pos: number, end: number;
|
||||
switch (kind) {
|
||||
case RefFileKind.Import:
|
||||
pos = skipTrivia(refFile.text, refFile.imports[index].pos);
|
||||
end = refFile.imports[index].end;
|
||||
break;
|
||||
case RefFileKind.ReferenceFile:
|
||||
({ pos, end } = refFile.referencedFiles[index]);
|
||||
break;
|
||||
case RefFileKind.TypeReferenceDirective:
|
||||
({ pos, end } = refFile.typeReferenceDirectives[index]);
|
||||
break;
|
||||
default:
|
||||
return Debug.assertNever(kind);
|
||||
}
|
||||
programDiagnostics.add(createFileDiagnostic(refFile, pos, end - pos, message, ...args));
|
||||
}
|
||||
else {
|
||||
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
|
||||
}
|
||||
}
|
||||
|
||||
function verifyProjectReferences() {
|
||||
const buildInfoPath = !options.noEmit && !options.suppressOutputPathCheck ? getOutputPathForBuildInfo(options) : undefined;
|
||||
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => {
|
||||
|
|
|
@ -2914,6 +2914,20 @@ namespace ts {
|
|||
throwIfCancellationRequested(): void;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export enum RefFileKind {
|
||||
Import,
|
||||
ReferenceFile,
|
||||
TypeReferenceDirective
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface RefFile {
|
||||
kind: RefFileKind;
|
||||
index: number;
|
||||
file: Path;
|
||||
}
|
||||
|
||||
// TODO: This should implement TypeCheckerHost but that's an internal type.
|
||||
export interface Program extends ScriptReferenceHost {
|
||||
|
||||
|
@ -2933,6 +2947,8 @@ namespace ts {
|
|||
*/
|
||||
/* @internal */
|
||||
getMissingFilePaths(): ReadonlyArray<Path>;
|
||||
/* @internal */
|
||||
getRefFileMap(): MultiMap<RefFile> | undefined;
|
||||
|
||||
/**
|
||||
* Emits the JavaScript and declaration files. If targetSourceFile is not specified, then
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace ts {
|
|||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string | undefined): Map<true>;
|
||||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => __String | undefined): UnderscoreEscapedMap<true>;
|
||||
export function arrayToSet(array: ReadonlyArray<any>, makeKey?: (value: any) => string | __String | undefined): Map<true> | UnderscoreEscapedMap<true> {
|
||||
return arrayToMap<any, true>(array, makeKey || (s => s), () => true);
|
||||
return arrayToMap<any, true>(array, makeKey || (s => s), returnTrue);
|
||||
}
|
||||
|
||||
export function cloneMap(map: SymbolTable): SymbolTable;
|
||||
|
|
|
@ -193,7 +193,7 @@ namespace ts {
|
|||
};
|
||||
|
||||
testProjectReferences(spec, "/primary/tsconfig.json", program => {
|
||||
const errs = program.getOptionsDiagnostics();
|
||||
const errs = program.getSemanticDiagnostics(program.getSourceFile("/primary/a.ts"));
|
||||
assertHasError("Reports an error about b.ts not being in the list", errs, Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern);
|
||||
});
|
||||
});
|
||||
|
@ -343,8 +343,9 @@ namespace ts {
|
|||
}
|
||||
};
|
||||
testProjectReferences(spec, "/alpha/tsconfig.json", (program) => {
|
||||
assertHasError("Issues an error about the rootDir", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files);
|
||||
assertHasError("Issues an error about the fileList", program.getOptionsDiagnostics(), Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern);
|
||||
const semanticDiagnostics = program.getSemanticDiagnostics(program.getSourceFile("/alpha/src/a.ts"));
|
||||
assertHasError("Issues an error about the rootDir", semanticDiagnostics, Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files);
|
||||
assertHasError("Issues an error about the fileList", semanticDiagnostics, Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace ts {
|
|||
interface VerifyBuild {
|
||||
modifyDiskLayout: (fs: vfs.FileSystem) => void;
|
||||
expectedExitStatus: ExitStatus;
|
||||
expectedDiagnostics: fakes.ExpectedDiagnostic[];
|
||||
expectedDiagnostics: (fs: vfs.FileSystem) => fakes.ExpectedDiagnostic[];
|
||||
expectedOutputs: readonly string[];
|
||||
notExpectedOutputs: readonly string[];
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace ts {
|
|||
const builder = createSolutionBuilder(host, ["/src/tsconfig.json"], { verbose: true });
|
||||
const exitStatus = builder.build();
|
||||
assert.equal(exitStatus, expectedExitStatus);
|
||||
host.assertDiagnosticMessages(...expectedDiagnostics);
|
||||
host.assertDiagnosticMessages(...expectedDiagnostics(fs));
|
||||
verifyOutputsPresent(fs, expectedOutputs);
|
||||
verifyOutputsAbsent(fs, notExpectedOutputs);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace ts {
|
|||
verifyBuild({
|
||||
modifyDiskLayout: noop,
|
||||
expectedExitStatus: ExitStatus.Success,
|
||||
expectedDiagnostics: [
|
||||
expectedDiagnostics: () => [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/animals/tsconfig.json", "src/zoo/tsconfig.json", "src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/lib/core/utilities.js"],
|
||||
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
|
||||
|
@ -91,7 +91,7 @@ namespace ts {
|
|||
]`
|
||||
),
|
||||
expectedExitStatus: ExitStatus.ProjectReferenceCycle_OutputsSkupped,
|
||||
expectedDiagnostics: [
|
||||
expectedDiagnostics: () => [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/animals/tsconfig.json", "src/zoo/tsconfig.json", "src/core/tsconfig.json", "src/tsconfig.json"),
|
||||
errorDiagnostic([
|
||||
Diagnostics.Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0,
|
||||
|
@ -117,16 +117,38 @@ namespace ts {
|
|||
`
|
||||
),
|
||||
expectedExitStatus: ExitStatus.DiagnosticsPresent_OutputsSkipped,
|
||||
expectedDiagnostics: [
|
||||
expectedDiagnostics: fs => [
|
||||
getExpectedDiagnosticForProjectsInBuild("src/core/tsconfig.json", "src/animals/tsconfig.json", "src/zoo/tsconfig.json", "src/tsconfig.json"),
|
||||
[Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, "src/core/tsconfig.json", "src/lib/core/utilities.js"],
|
||||
[Diagnostics.Building_project_0, "/src/core/tsconfig.json"],
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/animal.ts", "/src/core"]),
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/dog.ts", "/src/core"]),
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/index.ts", "/src/core"]),
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/animal.ts", "/src/core/tsconfig.json"]),
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/dog.ts", "/src/core/tsconfig.json"]),
|
||||
errorDiagnostic([Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/index.ts", "/src/core/tsconfig.json"]),
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/animal.ts", "/src/core"],
|
||||
location: expectedLocationIndexOf(fs, "/src/animals/index.ts", `'./animal'`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/animal.ts", "/src/core/tsconfig.json"],
|
||||
location: expectedLocationIndexOf(fs, "/src/animals/index.ts", `'./animal'`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/dog.ts", "/src/core"],
|
||||
location: expectedLocationIndexOf(fs, "/src/animals/index.ts", `'./dog'`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/dog.ts", "/src/core/tsconfig.json"],
|
||||
location: expectedLocationIndexOf(fs, "/src/animals/index.ts", `'./dog'`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics._0_is_declared_but_its_value_is_never_read, "A"],
|
||||
location: expectedLocationIndexOf(fs, "/src/core/utilities.ts", `import * as A from '../animals';`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, "/src/animals/index.ts", "/src/core"],
|
||||
location: expectedLocationIndexOf(fs, "/src/core/utilities.ts", `'../animals'`),
|
||||
},
|
||||
{
|
||||
message: [Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, "/src/animals/index.ts", "/src/core/tsconfig.json"],
|
||||
location: expectedLocationIndexOf(fs, "/src/core/utilities.ts", `'../animals'`),
|
||||
},
|
||||
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, "src/animals/tsconfig.json", "src/core"],
|
||||
[Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, "/src/animals/tsconfig.json", "/src/core"],
|
||||
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_was_not_built, "src/zoo/tsconfig.json", "src/animals"],
|
||||
|
|
|
@ -17,11 +17,7 @@ namespace ts {
|
|||
builder.build();
|
||||
host.assertDiagnosticMessages({
|
||||
message: [Diagnostics.The_files_list_in_config_file_0_is_empty, "/src/no-references/tsconfig.json"],
|
||||
location: {
|
||||
file: "/src/no-references/tsconfig.json",
|
||||
start: lastIndexOf(fs, "/src/no-references/tsconfig.json", "[]"),
|
||||
length: 2
|
||||
}
|
||||
location: expectedLocationLastIndexOf(fs, "/src/no-references/tsconfig.json", "[]"),
|
||||
});
|
||||
|
||||
// Check for outputs to not be written.
|
||||
|
|
|
@ -62,6 +62,22 @@ namespace ts {
|
|||
return content.lastIndexOf(searchStr);
|
||||
}
|
||||
|
||||
export function expectedLocationIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation {
|
||||
return {
|
||||
file,
|
||||
start: indexOf(fs, file, searchStr),
|
||||
length: searchStr.length
|
||||
};
|
||||
}
|
||||
|
||||
export function expectedLocationLastIndexOf(fs: vfs.FileSystem, file: string, searchStr: string): fakes.ExpectedDiagnosticLocation {
|
||||
return {
|
||||
file,
|
||||
start: lastIndexOf(fs, file, searchStr),
|
||||
length: searchStr.length
|
||||
};
|
||||
}
|
||||
|
||||
export function getTime() {
|
||||
let currentTime = 100;
|
||||
return { tick, time, touch };
|
||||
|
|
|
@ -45,11 +45,7 @@ namespace ts {
|
|||
[Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"],
|
||||
{
|
||||
message: [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"],
|
||||
location: {
|
||||
file: "/src/src/main/tsconfig.json",
|
||||
start: indexOf(fs, "/src/src/main/tsconfig.json", `{ "path": "../other" }`),
|
||||
length: `{ "path": "../other" }`.length
|
||||
}
|
||||
location: expectedLocationIndexOf(fs, "/src/src/main/tsconfig.json", `{ "path": "../other" }`),
|
||||
}
|
||||
);
|
||||
verifyOutputsPresent(fs, allExpectedOutputs);
|
||||
|
@ -84,11 +80,7 @@ namespace ts {
|
|||
[Diagnostics.Building_project_0, "/src/src/main/tsconfig.json"],
|
||||
{
|
||||
message: [Diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, "/src/dist/tsconfig.tsbuildinfo", "/src/src/other"],
|
||||
location: {
|
||||
file: "/src/src/main/tsconfig.json",
|
||||
start: indexOf(fs, "/src/src/main/tsconfig.json", `{"path":"../other"}`),
|
||||
length: `{"path":"../other"}`.length
|
||||
}
|
||||
location: expectedLocationIndexOf(fs, "/src/src/main/tsconfig.json", `{"path":"../other"}`),
|
||||
}
|
||||
);
|
||||
verifyOutputsPresent(fs, allExpectedOutputs);
|
||||
|
|
|
@ -30,11 +30,14 @@ namespace ts {
|
|||
it("with resolveJsonModule and include only", () => {
|
||||
verifyProjectWithResolveJsonModule(
|
||||
"/src/tsconfig_withInclude.json",
|
||||
errorDiagnostic([
|
||||
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
|
||||
"/src/src/hello.json",
|
||||
"/src/tsconfig_withInclude.json"
|
||||
])
|
||||
{
|
||||
message: [
|
||||
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
|
||||
"/src/src/hello.json",
|
||||
"/src/tsconfig_withInclude.json"
|
||||
],
|
||||
location: expectedLocationIndexOf(projFs, "/src/src/index.ts", `"./hello.json"`)
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -452,11 +452,7 @@ namespace ts {
|
|||
[Diagnostics.Building_project_0, "/src/logic/tsconfig.json"],
|
||||
{
|
||||
message: [Diagnostics.Property_0_does_not_exist_on_type_1, "muitply", `typeof import("/src/core/index")`],
|
||||
location: {
|
||||
file: "/src/logic/index.ts",
|
||||
start: indexOf(fs, "/src/logic/index.ts", "muitply"),
|
||||
length: "muitply".length
|
||||
}
|
||||
location: expectedLocationIndexOf(fs, "/src/logic/index.ts", "muitply"),
|
||||
},
|
||||
[Diagnostics.Project_0_can_t_be_built_because_its_dependency_1_has_errors, "src/tests/tsconfig.json", "src/logic"],
|
||||
[Diagnostics.Skipping_build_of_project_0_because_its_dependency_1_has_errors, "/src/tests/tsconfig.json", "/src/logic"]
|
||||
|
|
|
@ -1295,6 +1295,62 @@ export function someFn() { }`);
|
|||
]);
|
||||
});
|
||||
|
||||
it("updates with bad reference", () => {
|
||||
const host = createTsBuildWatchSystem([
|
||||
...allFilesExceptBase,
|
||||
baseConfig,
|
||||
{ path: libFile.path, content: libContent }
|
||||
], { currentDirectory: projectLocation });
|
||||
host.writeFile(coreFiles[1].path, `import * as A from '../animals';
|
||||
${coreFiles[1].content}`);
|
||||
createSolutionBuilderWithWatch(host, ["tsconfig.json"], { verbose: true, watch: true });
|
||||
const errors = [
|
||||
`animals/index.ts(1,20): error TS6059: File '/user/username/projects/demo/animals/animal.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`animals/index.ts(1,20): error TS6307: File '/user/username/projects/demo/animals/animal.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`,
|
||||
`animals/index.ts(4,32): error TS6059: File '/user/username/projects/demo/animals/dog.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`animals/index.ts(4,32): error TS6307: File '/user/username/projects/demo/animals/dog.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`,
|
||||
`core/utilities.ts(1,1): error TS6133: 'A' is declared but its value is never read.\n`,
|
||||
`core/utilities.ts(1,20): error TS6059: File '/user/username/projects/demo/animals/index.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`core/utilities.ts(1,20): error TS6307: File '/user/username/projects/demo/animals/index.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`
|
||||
].map(hostOutputDiagnostic);
|
||||
checkOutputErrors(host, [
|
||||
startingCompilationInWatchMode(),
|
||||
hostOutputLog(`Projects in this build: \r\n * core/tsconfig.json\r\n * animals/tsconfig.json\r\n * zoo/tsconfig.json\r\n * tsconfig.json\n\n`),
|
||||
hostOutputLog(`Project 'core/tsconfig.json' is out of date because output file 'lib/core/utilities.js' does not exist\n\n`),
|
||||
hostOutputLog(`Building project '/user/username/projects/demo/core/tsconfig.json'...\n\n`),
|
||||
...errors,
|
||||
hostOutputLog(`Project 'animals/tsconfig.json' can't be built because its dependency 'core' has errors\n\n`),
|
||||
hostOutputLog(`Skipping build of project '/user/username/projects/demo/animals/tsconfig.json' because its dependency '/user/username/projects/demo/core' has errors\n\n`),
|
||||
hostOutputLog(`Project 'zoo/tsconfig.json' can't be built because its dependency 'animals' was not built\n\n`),
|
||||
hostOutputLog(`Skipping build of project '/user/username/projects/demo/zoo/tsconfig.json' because its dependency '/user/username/projects/demo/animals' was not built\n\n`),
|
||||
foundErrorsWatching(errors)
|
||||
]);
|
||||
verifyWatches(host);
|
||||
|
||||
// Make changes
|
||||
host.writeFile(coreFiles[1].path, `
|
||||
import * as A from '../animals';
|
||||
${coreFiles[1].content}`);
|
||||
const newErrors = [
|
||||
`animals/index.ts(1,20): error TS6059: File '/user/username/projects/demo/animals/animal.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`animals/index.ts(1,20): error TS6307: File '/user/username/projects/demo/animals/animal.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`,
|
||||
`animals/index.ts(4,32): error TS6059: File '/user/username/projects/demo/animals/dog.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`animals/index.ts(4,32): error TS6307: File '/user/username/projects/demo/animals/dog.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`,
|
||||
`core/utilities.ts(2,1): error TS6133: 'A' is declared but its value is never read.\n`,
|
||||
`core/utilities.ts(2,20): error TS6059: File '/user/username/projects/demo/animals/index.ts' is not under 'rootDir' '/user/username/projects/demo/core'. 'rootDir' is expected to contain all source files.\n`,
|
||||
`core/utilities.ts(2,20): error TS6307: File '/user/username/projects/demo/animals/index.ts' is not listed within the file list of project '/user/username/projects/demo/core/tsconfig.json'. Projects must list all files or use an 'include' pattern.\n`
|
||||
].map(hostOutputDiagnostic);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // build core
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrors(host, [
|
||||
fileChangeDetected(),
|
||||
hostOutputLog(`Project 'core/tsconfig.json' is out of date because output file 'lib/core/utilities.js' does not exist\n\n`),
|
||||
hostOutputLog(`Building project '/user/username/projects/demo/core/tsconfig.json'...\n\n`),
|
||||
...newErrors,
|
||||
foundErrorsWatching(newErrors)
|
||||
]);
|
||||
});
|
||||
|
||||
function subProjectFiles(subProject: string, fileNames: readonly string[]): File[] {
|
||||
return fileNames.map(file => projectFile(`${subProject}/${file}`));
|
||||
}
|
||||
|
|
|
@ -54,30 +54,51 @@ namespace ts.tscWatch {
|
|||
|
||||
const elapsedRegex = /^Elapsed:: [0-9]+ms/;
|
||||
const buildVerboseLogRegEx = /^.+ \- /;
|
||||
function checkOutputErrors(
|
||||
export enum HostOutputKind {
|
||||
Log,
|
||||
Diagnostic,
|
||||
WatchDiagnostic
|
||||
}
|
||||
|
||||
export interface HostOutputLog {
|
||||
kind: HostOutputKind.Log;
|
||||
expected: string;
|
||||
caption?: string;
|
||||
}
|
||||
|
||||
export interface HostOutputDiagnostic {
|
||||
kind: HostOutputKind.Diagnostic;
|
||||
diagnostic: Diagnostic | string;
|
||||
}
|
||||
|
||||
export interface HostOutputWatchDiagnostic {
|
||||
kind: HostOutputKind.WatchDiagnostic;
|
||||
diagnostic: Diagnostic | string;
|
||||
}
|
||||
|
||||
export type HostOutput = HostOutputLog | HostOutputDiagnostic | HostOutputWatchDiagnostic;
|
||||
|
||||
export function checkOutputErrors(
|
||||
host: WatchedSystem,
|
||||
logsBeforeWatchDiagnostic: string[] | undefined,
|
||||
preErrorsWatchDiagnostic: Diagnostic | undefined,
|
||||
logsBeforeErrors: string[] | undefined,
|
||||
errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>,
|
||||
disableConsoleClears?: boolean | undefined,
|
||||
...postErrorsWatchDiagnostics: Diagnostic[] | string[]
|
||||
expected: readonly HostOutput[],
|
||||
disableConsoleClears?: boolean | undefined
|
||||
) {
|
||||
let screenClears = 0;
|
||||
const outputs = host.getOutput();
|
||||
const expectedOutputCount = (preErrorsWatchDiagnostic ? 1 : 0) +
|
||||
errors.length +
|
||||
postErrorsWatchDiagnostics.length +
|
||||
(logsBeforeWatchDiagnostic ? logsBeforeWatchDiagnostic.length : 0) +
|
||||
(logsBeforeErrors ? logsBeforeErrors.length : 0);
|
||||
assert.equal(outputs.length, expectedOutputCount, JSON.stringify(outputs));
|
||||
assert.equal(outputs.length, expected.length, JSON.stringify(outputs));
|
||||
let index = 0;
|
||||
forEach(logsBeforeWatchDiagnostic, log => assertLog("logsBeforeWatchDiagnostic", log));
|
||||
if (preErrorsWatchDiagnostic) assertWatchDiagnostic(preErrorsWatchDiagnostic);
|
||||
forEach(logsBeforeErrors, log => assertLog("logBeforeError", log));
|
||||
// Verify errors
|
||||
forEach(errors, assertDiagnostic);
|
||||
forEach(postErrorsWatchDiagnostics, assertWatchDiagnostic);
|
||||
forEach(expected, expected => {
|
||||
switch (expected.kind) {
|
||||
case HostOutputKind.Log:
|
||||
return assertLog(expected);
|
||||
case HostOutputKind.Diagnostic:
|
||||
return assertDiagnostic(expected);
|
||||
case HostOutputKind.WatchDiagnostic:
|
||||
return assertWatchDiagnostic(expected);
|
||||
default:
|
||||
return Debug.assertNever(expected);
|
||||
}
|
||||
});
|
||||
assert.equal(host.screenClears.length, screenClears, "Expected number of screen clears");
|
||||
host.clearOutput();
|
||||
|
||||
|
@ -85,7 +106,7 @@ namespace ts.tscWatch {
|
|||
return !!(diagnostic as Diagnostic).messageText;
|
||||
}
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic | string) {
|
||||
function assertDiagnostic({ diagnostic }: HostOutputDiagnostic) {
|
||||
const expected = isDiagnostic(diagnostic) ? formatDiagnostic(diagnostic, host) : diagnostic;
|
||||
assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected));
|
||||
index++;
|
||||
|
@ -95,13 +116,13 @@ namespace ts.tscWatch {
|
|||
return log.replace(elapsedRegex, "").replace(buildVerboseLogRegEx, "");
|
||||
}
|
||||
|
||||
function assertLog(caption: string, expected: string) {
|
||||
function assertLog({ caption, expected }: HostOutputLog) {
|
||||
const actual = outputs[index];
|
||||
assert.equal(getCleanLogString(actual), getCleanLogString(expected), getOutputAtFailedMessage(caption, expected));
|
||||
assert.equal(getCleanLogString(actual), getCleanLogString(expected), getOutputAtFailedMessage(caption || "Log", expected));
|
||||
index++;
|
||||
}
|
||||
|
||||
function assertWatchDiagnostic(diagnostic: Diagnostic | string) {
|
||||
function assertWatchDiagnostic({ diagnostic }: HostOutputWatchDiagnostic) {
|
||||
if (isString(diagnostic)) {
|
||||
assert.equal(outputs[index], diagnostic, getOutputAtFailedMessage("Diagnostic", diagnostic));
|
||||
}
|
||||
|
@ -128,54 +149,82 @@ namespace ts.tscWatch {
|
|||
}
|
||||
}
|
||||
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>) {
|
||||
return errors.length === 1
|
||||
? createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes)
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
export function hostOutputLog(expected: string, caption?: string): HostOutputLog {
|
||||
return { kind: HostOutputKind.Log, expected, caption };
|
||||
}
|
||||
export function hostOutputDiagnostic(diagnostic: Diagnostic | string): HostOutputDiagnostic {
|
||||
return { kind: HostOutputKind.Diagnostic, diagnostic };
|
||||
}
|
||||
export function hostOutputWatchDiagnostic(diagnostic: Diagnostic | string): HostOutputWatchDiagnostic {
|
||||
return { kind: HostOutputKind.WatchDiagnostic, diagnostic };
|
||||
}
|
||||
|
||||
export function startingCompilationInWatchMode() {
|
||||
return hostOutputWatchDiagnostic(createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode));
|
||||
}
|
||||
export function foundErrorsWatching(errors: readonly any[]) {
|
||||
return hostOutputWatchDiagnostic(errors.length === 1 ?
|
||||
createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes) :
|
||||
createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length)
|
||||
);
|
||||
}
|
||||
export function fileChangeDetected() {
|
||||
return hostOutputWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
|
||||
}
|
||||
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
createCompilerDiagnostic(Diagnostics.Starting_compilation_in_watch_mode),
|
||||
logsBeforeErrors,
|
||||
errors,
|
||||
disableConsoleClears,
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
[
|
||||
startingCompilationInWatchMode(),
|
||||
...map(logsBeforeErrors || emptyArray, expected => hostOutputLog(expected, "logBeforeError")),
|
||||
...map(errors, hostOutputDiagnostic),
|
||||
foundErrorsWatching(errors)
|
||||
],
|
||||
disableConsoleClears
|
||||
);
|
||||
}
|
||||
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation),
|
||||
logsBeforeErrors,
|
||||
errors,
|
||||
disableConsoleClears,
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
[
|
||||
...map(logsBeforeWatchDiagnostic || emptyArray, expected => hostOutputLog(expected, "logsBeforeWatchDiagnostic")),
|
||||
fileChangeDetected(),
|
||||
...map(logsBeforeErrors || emptyArray, expected => hostOutputLog(expected, "logBeforeError")),
|
||||
...map(errors, hostOutputDiagnostic),
|
||||
foundErrorsWatching(errors)
|
||||
],
|
||||
disableConsoleClears
|
||||
);
|
||||
}
|
||||
|
||||
export function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation),
|
||||
logsBeforeErrors,
|
||||
errors,
|
||||
disableConsoleClears);
|
||||
[
|
||||
...map(logsBeforeWatchDiagnostic || emptyArray, expected => hostOutputLog(expected, "logsBeforeWatchDiagnostic")),
|
||||
fileChangeDetected(),
|
||||
...map(logsBeforeErrors || emptyArray, expected => hostOutputLog(expected, "logBeforeError")),
|
||||
...map(errors, hostOutputDiagnostic),
|
||||
],
|
||||
disableConsoleClears
|
||||
);
|
||||
assert.equal(host.exitCode, expectedExitCode);
|
||||
}
|
||||
|
||||
export function checkNormalBuildErrors(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, reportErrorSummary?: boolean) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
/*preErrorsWatchDiagnostic*/ undefined,
|
||||
/*logsBeforeErrors*/ undefined,
|
||||
errors,
|
||||
/*disableConsoleClears*/ undefined,
|
||||
...(reportErrorSummary ? [getErrorSummaryText(errors.length, host.newLine)] : emptyArray)
|
||||
[
|
||||
...map(errors, hostOutputDiagnostic),
|
||||
...map(
|
||||
reportErrorSummary ?
|
||||
[getErrorSummaryText(errors.length, host.newLine)] :
|
||||
emptyArray,
|
||||
hostOutputWatchDiagnostic
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1335,5 +1335,42 @@ exports.a = 1;
|
|||
checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]);
|
||||
}
|
||||
});
|
||||
|
||||
it("reports errors correctly with file not in rootDir", () => {
|
||||
const currentDirectory = "/user/username/projects/myproject";
|
||||
const aFile: File = {
|
||||
path: `${currentDirectory}/a.ts`,
|
||||
content: `import { x } from "../b";`
|
||||
};
|
||||
const bFile: File = {
|
||||
path: `/user/username/projects/b.ts`,
|
||||
content: `export const x = 10;`
|
||||
};
|
||||
const configFile: File = {
|
||||
path: `${currentDirectory}/tsconfig.json`,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: {
|
||||
rootDir: ".",
|
||||
outDir: "lib"
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
const files = [aFile, bFile, libFile, configFile];
|
||||
|
||||
const host = createWatchedSystem(files, { currentDirectory });
|
||||
const watch = createWatchOfConfigFile("tsconfig.json", host);
|
||||
checkOutputErrorsInitial(host, [
|
||||
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.indexOf(`"../b"`), `"../b"`.length, Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, bFile.path, currentDirectory)
|
||||
]);
|
||||
const aContent = `
|
||||
|
||||
${aFile.content}`;
|
||||
host.writeFile(aFile.path, aContent);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
checkOutputErrorsIncremental(host, [
|
||||
getDiagnosticOfFileFromProgram(watch(), aFile.path, aContent.indexOf(`"../b"`), `"../b"`.length, Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, bFile.path, currentDirectory)
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue