mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Handle module node found error reporting in incremental and watch scneario (#54115)
This commit is contained in:
+91
-4
@@ -22,6 +22,7 @@ import {
|
||||
convertToOptionsWithAbsolutePaths,
|
||||
createBuildInfo,
|
||||
createGetCanonicalFileName,
|
||||
createModuleNotFoundChain,
|
||||
createProgram,
|
||||
CustomTransformers,
|
||||
Debug,
|
||||
@@ -68,8 +69,11 @@ import {
|
||||
ProjectReference,
|
||||
ReadBuildProgramHost,
|
||||
ReadonlyCollection,
|
||||
RepopulateDiagnosticChainInfo,
|
||||
RepopulateModuleNotFoundDiagnosticChain,
|
||||
returnFalse,
|
||||
returnUndefined,
|
||||
sameMap,
|
||||
SemanticDiagnosticsBuilderProgram,
|
||||
skipTypeChecking,
|
||||
some,
|
||||
@@ -103,7 +107,18 @@ export interface ReusableDiagnosticRelatedInformation {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type ReusableDiagnosticMessageChain = DiagnosticMessageChain;
|
||||
export interface ReusableRepopulateModuleNotFoundChain {
|
||||
info: RepopulateModuleNotFoundDiagnosticChain;
|
||||
next?: ReusableDiagnosticMessageChain[];
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type SerializedDiagnosticMessageChain = Omit<DiagnosticMessageChain, "next" | "repopulateInfo"> & {
|
||||
next?: ReusableDiagnosticMessageChain[];
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export type ReusableDiagnosticMessageChain = SerializedDiagnosticMessageChain | ReusableRepopulateModuleNotFoundChain;
|
||||
|
||||
/**
|
||||
* Signature (Hash of d.ts emitted), is string if it was emitted using same d.ts.map option as what compilerOptions indicate, otherwise tuple of string
|
||||
@@ -364,7 +379,12 @@ function createBuilderProgramState(newProgram: Program, oldState: Readonly<Reusa
|
||||
// Unchanged file copy diagnostics
|
||||
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
|
||||
if (diagnostics) {
|
||||
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as readonly ReusableDiagnostic[], newProgram) : diagnostics as readonly Diagnostic[]);
|
||||
state.semanticDiagnosticsPerFile!.set(
|
||||
sourceFilePath,
|
||||
oldState!.hasReusableDiagnostic ?
|
||||
convertToDiagnostics(diagnostics as readonly ReusableDiagnostic[], newProgram) :
|
||||
repopulateDiagnostics(diagnostics as readonly Diagnostic[], newProgram)
|
||||
);
|
||||
if (!state.semanticDiagnosticsFromOldState) {
|
||||
state.semanticDiagnosticsFromOldState = new Set();
|
||||
}
|
||||
@@ -448,6 +468,43 @@ function getEmitSignatureFromOldSignature(options: CompilerOptions, oldOptions:
|
||||
isString(oldEmitSignature) ? [oldEmitSignature] : oldEmitSignature[0];
|
||||
}
|
||||
|
||||
function repopulateDiagnostics(diagnostics: readonly Diagnostic[], newProgram: Program): readonly Diagnostic[] {
|
||||
if (!diagnostics.length) return diagnostics;
|
||||
return sameMap(diagnostics, diag => {
|
||||
if (isString(diag.messageText)) return diag;
|
||||
const repopulatedChain = convertOrRepopulateDiagnosticMessageChain(diag.messageText, diag.file, newProgram, chain => chain.repopulateInfo?.());
|
||||
return repopulatedChain === diag.messageText ?
|
||||
diag :
|
||||
{ ...diag, messageText: repopulatedChain };
|
||||
});
|
||||
}
|
||||
|
||||
function convertOrRepopulateDiagnosticMessageChain<T extends DiagnosticMessageChain | ReusableDiagnosticMessageChain>(
|
||||
chain: T,
|
||||
sourceFile: SourceFile | undefined,
|
||||
newProgram: Program,
|
||||
repopulateInfo: (chain: T) => RepopulateDiagnosticChainInfo | undefined,
|
||||
): DiagnosticMessageChain {
|
||||
const info = repopulateInfo(chain);
|
||||
if (info) {
|
||||
return {
|
||||
...createModuleNotFoundChain(sourceFile!, newProgram, info.moduleReference, info.mode, info.packageName || info.moduleReference),
|
||||
next: convertOrRepopulateDiagnosticMessageChainArray(chain.next as T[], sourceFile, newProgram, repopulateInfo),
|
||||
};
|
||||
}
|
||||
const next = convertOrRepopulateDiagnosticMessageChainArray(chain.next as T[], sourceFile, newProgram, repopulateInfo);
|
||||
return next === chain.next ? chain as DiagnosticMessageChain : { ...chain as DiagnosticMessageChain, next };
|
||||
}
|
||||
|
||||
function convertOrRepopulateDiagnosticMessageChainArray<T extends DiagnosticMessageChain | ReusableDiagnosticMessageChain>(
|
||||
array: T[] | undefined,
|
||||
sourceFile: SourceFile | undefined,
|
||||
newProgram: Program,
|
||||
repopulateInfo: (chain: T) => RepopulateDiagnosticChainInfo | undefined,
|
||||
): DiagnosticMessageChain[] | undefined {
|
||||
return sameMap(array, chain => convertOrRepopulateDiagnosticMessageChain(chain, sourceFile, newProgram, repopulateInfo));
|
||||
}
|
||||
|
||||
function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newProgram: Program): readonly Diagnostic[] {
|
||||
if (!diagnostics.length) return emptyArray;
|
||||
let buildInfoDirectory: string | undefined;
|
||||
@@ -474,9 +531,13 @@ function convertToDiagnostics(diagnostics: readonly ReusableDiagnostic[], newPro
|
||||
|
||||
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
|
||||
const { file } = diagnostic;
|
||||
const sourceFile = file ? newProgram.getSourceFileByPath(toPath(file)) : undefined;
|
||||
return {
|
||||
...diagnostic,
|
||||
file: file ? newProgram.getSourceFileByPath(toPath(file)) : undefined
|
||||
file: sourceFile,
|
||||
messageText: isString(diagnostic.messageText) ?
|
||||
diagnostic.messageText :
|
||||
convertOrRepopulateDiagnosticMessageChain(diagnostic.messageText, sourceFile, newProgram, chain => (chain as ReusableRepopulateModuleNotFoundChain).info),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1232,10 +1293,36 @@ function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRel
|
||||
const { file } = diagnostic;
|
||||
return {
|
||||
...diagnostic,
|
||||
file: file ? relativeToBuildInfo(file.resolvedPath) : undefined
|
||||
file: file ? relativeToBuildInfo(file.resolvedPath) : undefined,
|
||||
messageText: isString(diagnostic.messageText) ? diagnostic.messageText : convertToReusableDiagnosticMessageChain(diagnostic.messageText),
|
||||
};
|
||||
}
|
||||
|
||||
function convertToReusableDiagnosticMessageChain(chain: DiagnosticMessageChain): ReusableDiagnosticMessageChain {
|
||||
if (chain.repopulateInfo) {
|
||||
return {
|
||||
info: chain.repopulateInfo(),
|
||||
next: convertToReusableDiagnosticMessageChainArray(chain.next),
|
||||
};
|
||||
}
|
||||
const next = convertToReusableDiagnosticMessageChainArray(chain.next);
|
||||
return next === chain.next ? chain : { ...chain, next };
|
||||
}
|
||||
|
||||
function convertToReusableDiagnosticMessageChainArray(array: DiagnosticMessageChain[] | undefined): ReusableDiagnosticMessageChain[] | undefined {
|
||||
if (!array) return array;
|
||||
return forEach(array, (chain, index) => {
|
||||
const reusable = convertToReusableDiagnosticMessageChain(chain);
|
||||
if (chain === reusable) return undefined;
|
||||
const result: ReusableDiagnosticMessageChain[] = index > 0 ? array.slice(0, index - 1) : [];
|
||||
result.push(reusable);
|
||||
for (let i = index + 1; i < array.length; i++) {
|
||||
result.push(convertToReusableDiagnosticMessageChain(array[i]));
|
||||
}
|
||||
return result;
|
||||
}) || array;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export enum BuilderProgramKind {
|
||||
SemanticDiagnosticsBuilderProgram,
|
||||
|
||||
+3
-50
@@ -110,6 +110,7 @@ import {
|
||||
createGetCanonicalFileName,
|
||||
createGetSymbolWalker,
|
||||
createModeAwareCacheKey,
|
||||
createModuleNotFoundChain,
|
||||
createMultiMap,
|
||||
createPrinterWithDefaults,
|
||||
createPrinterWithRemoveComments,
|
||||
@@ -359,7 +360,6 @@ import {
|
||||
getThisParameter,
|
||||
getTrailingSemicolonDeferringWriter,
|
||||
getTypeParameterFromJsDoc,
|
||||
getTypesPackageName,
|
||||
getUseDefineForClassFields,
|
||||
group,
|
||||
hasAbstractModifier,
|
||||
@@ -806,7 +806,6 @@ import {
|
||||
LiteralExpression,
|
||||
LiteralType,
|
||||
LiteralTypeNode,
|
||||
mangleScopedPackageName,
|
||||
map,
|
||||
mapDefined,
|
||||
MappedSymbol,
|
||||
@@ -815,7 +814,6 @@ import {
|
||||
MatchingKeys,
|
||||
maybeBind,
|
||||
MemberOverrideStatus,
|
||||
memoize,
|
||||
MetaProperty,
|
||||
MethodDeclaration,
|
||||
MethodSignature,
|
||||
@@ -853,7 +851,6 @@ import {
|
||||
nodeIsPresent,
|
||||
nodeIsSynthesized,
|
||||
NodeLinks,
|
||||
nodeModulesPathPart,
|
||||
nodeStartsNewLexicalEnvironment,
|
||||
NodeWithTypeArguments,
|
||||
NonNullChain,
|
||||
@@ -1392,22 +1389,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// Why var? It avoids TDZ checks in the runtime which can be costly.
|
||||
// See: https://github.com/microsoft/TypeScript/issues/52924
|
||||
/* eslint-disable no-var */
|
||||
var getPackagesMap = memoize(() => {
|
||||
// A package name maps to true when we detect it has .d.ts files.
|
||||
// This is useful as an approximation of whether a package bundles its own types.
|
||||
// Note: we only look at files already found by module resolution,
|
||||
// so there may be files we did not consider.
|
||||
var map = new Map<string, boolean>();
|
||||
host.getSourceFiles().forEach(sf => {
|
||||
if (!sf.resolvedModules) return;
|
||||
|
||||
sf.resolvedModules.forEach(({ resolvedModule }) => {
|
||||
if (resolvedModule?.packageId) map.set(resolvedModule.packageId.name, resolvedModule.extension === Extension.Dts || !!map.get(resolvedModule.packageId.name));
|
||||
});
|
||||
});
|
||||
return map;
|
||||
});
|
||||
|
||||
var deferredDiagnosticsCallbacks: (() => void)[] = [];
|
||||
|
||||
var addLazyDiagnostic = (arg: () => void) => {
|
||||
@@ -5068,31 +5049,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, sourceFile: SourceFile, mode: ResolutionMode, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void {
|
||||
let errorInfo;
|
||||
let errorInfo: DiagnosticMessageChain | undefined;
|
||||
if (!isExternalModuleNameRelative(moduleReference) && packageId) {
|
||||
const node10Result = sourceFile.resolvedModules?.get(moduleReference, mode)?.node10Result;
|
||||
errorInfo = node10Result
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.There_are_types_at_0_but_this_result_could_not_be_resolved_when_respecting_package_json_exports_The_1_library_may_need_to_update_its_package_json_or_typings,
|
||||
node10Result,
|
||||
node10Result.indexOf(nodeModulesPathPart + "@types/") > -1 ? `@types/${mangleScopedPackageName(packageId.name)}` : packageId.name)
|
||||
: typesPackageExists(packageId.name)
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1,
|
||||
packageId.name, mangleScopedPackageName(packageId.name))
|
||||
: packageBundlesTypes(packageId.name)
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1,
|
||||
packageId.name,
|
||||
moduleReference)
|
||||
: chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0,
|
||||
moduleReference,
|
||||
mangleScopedPackageName(packageId.name));
|
||||
errorInfo = createModuleNotFoundChain(sourceFile, host, moduleReference, mode, packageId.name);
|
||||
}
|
||||
errorOrSuggestion(isError, errorNode, chainDiagnosticMessages(
|
||||
errorInfo,
|
||||
@@ -5100,12 +5059,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
moduleReference,
|
||||
resolvedFileName));
|
||||
}
|
||||
function typesPackageExists(packageName: string): boolean {
|
||||
return getPackagesMap().has(getTypesPackageName(packageName));
|
||||
}
|
||||
function packageBundlesTypes(packageName: string): boolean {
|
||||
return !!getPackagesMap().get(packageName);
|
||||
}
|
||||
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined;
|
||||
|
||||
@@ -364,21 +364,21 @@ export function *mapIterator<T, U>(iter: Iterable<T>, mapFn: (x: T) => U) {
|
||||
* Maps from T to T and avoids allocation if all elements map to themselves
|
||||
*
|
||||
* @internal */
|
||||
export function sameMap<T>(array: T[], f: (x: T, i: number) => T): T[];
|
||||
export function sameMap<T, U = T>(array: T[], f: (x: T, i: number) => U): U[];
|
||||
/** @internal */
|
||||
export function sameMap<T>(array: readonly T[], f: (x: T, i: number) => T): readonly T[];
|
||||
export function sameMap<T, U = T>(array: readonly T[], f: (x: T, i: number) => U): readonly U[];
|
||||
/** @internal */
|
||||
export function sameMap<T>(array: T[] | undefined, f: (x: T, i: number) => T): T[] | undefined;
|
||||
export function sameMap<T, U = T>(array: T[] | undefined, f: (x: T, i: number) => U): U[] | undefined;
|
||||
/** @internal */
|
||||
export function sameMap<T>(array: readonly T[] | undefined, f: (x: T, i: number) => T): readonly T[] | undefined;
|
||||
export function sameMap<T, U = T>(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined;
|
||||
/** @internal */
|
||||
export function sameMap<T>(array: readonly T[] | undefined, f: (x: T, i: number) => T): readonly T[] | undefined {
|
||||
export function sameMap<T, U = T>(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined {
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const mapped = f(item, i);
|
||||
if (item !== mapped) {
|
||||
const result = array.slice(0, i);
|
||||
if (item as unknown !== mapped) {
|
||||
const result: U[] = array.slice(0, i) as unknown[] as U[];
|
||||
result.push(mapped);
|
||||
for (i++; i < array.length; i++) {
|
||||
result.push(f(array[i], i));
|
||||
@@ -387,7 +387,7 @@ export function sameMap<T>(array: readonly T[] | undefined, f: (x: T, i: number)
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
return array as unknown[] as U[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1758,8 +1758,6 @@ function nodeModuleNameResolverWorker(features: NodeResolutionFeatures, moduleNa
|
||||
const diagnosticState = {
|
||||
...state,
|
||||
features: state.features & ~NodeResolutionFeatures.Exports,
|
||||
failedLookupLocations: [],
|
||||
affectingLocations: [],
|
||||
reportDiagnostic: noop,
|
||||
};
|
||||
const diagnosticResult = tryResolve(extensions & (Extensions.TypeScript | Extensions.Declaration), diagnosticState);
|
||||
|
||||
@@ -153,6 +153,7 @@ import {
|
||||
getTsBuildInfoEmitOutputFilePath,
|
||||
getTsConfigObjectLiteralExpression,
|
||||
getTsConfigPropArrayElementValue,
|
||||
getTypesPackageName,
|
||||
HasChangedAutomaticTypeDirectiveNames,
|
||||
hasChangesInResolutions,
|
||||
hasExtension,
|
||||
@@ -1505,6 +1506,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
let resolvedLibReferences: Map<string, LibResolution> | undefined;
|
||||
let resolvedLibProcessing: Map<string, LibResolution> | undefined;
|
||||
|
||||
let packageMap: Map<string, boolean> | undefined;
|
||||
|
||||
|
||||
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
|
||||
// This works as imported modules are discovered recursively in a depth first manner, specifically:
|
||||
// - For each root file, findSourceFile is called.
|
||||
@@ -1862,6 +1866,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
redirectTargetsMap,
|
||||
usesUriStyleNodeCoreModules,
|
||||
resolvedLibReferences,
|
||||
getCurrentPackagesMap: () => packageMap,
|
||||
typesPackageExists,
|
||||
packageBundlesTypes,
|
||||
isEmittedFile,
|
||||
getConfigFileParsingDiagnostics,
|
||||
getProjectReferences,
|
||||
@@ -1908,6 +1915,30 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
|
||||
return program;
|
||||
|
||||
function getPackagesMap() {
|
||||
if (packageMap) return packageMap;
|
||||
packageMap = new Map();
|
||||
// A package name maps to true when we detect it has .d.ts files.
|
||||
// This is useful as an approximation of whether a package bundles its own types.
|
||||
// Note: we only look at files already found by module resolution,
|
||||
// so there may be files we did not consider.
|
||||
files.forEach(sf => {
|
||||
if (!sf.resolvedModules) return;
|
||||
|
||||
sf.resolvedModules.forEach(({ resolvedModule }) => {
|
||||
if (resolvedModule?.packageId) packageMap!.set(resolvedModule.packageId.name, resolvedModule.extension === Extension.Dts || !!packageMap!.get(resolvedModule.packageId.name));
|
||||
});
|
||||
});
|
||||
return packageMap;
|
||||
}
|
||||
|
||||
function typesPackageExists(packageName: string): boolean {
|
||||
return getPackagesMap().has(getTypesPackageName(packageName));
|
||||
}
|
||||
function packageBundlesTypes(packageName: string): boolean {
|
||||
return !!getPackagesMap().get(packageName);
|
||||
}
|
||||
|
||||
function addResolutionDiagnostics(resolution: ResolvedModuleWithFailedLookupLocations | ResolvedTypeReferenceDirectiveWithFailedLookupLocations) {
|
||||
if (!resolution.resolutionDiagnostics?.length) return;
|
||||
(fileProcessingDiagnostics ??= []).push({
|
||||
@@ -2536,6 +2567,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
||||
redirectTargetsMap = oldProgram.redirectTargetsMap;
|
||||
usesUriStyleNodeCoreModules = oldProgram.usesUriStyleNodeCoreModules;
|
||||
resolvedLibReferences = oldProgram.resolvedLibReferences;
|
||||
packageMap = oldProgram.getCurrentPackagesMap();
|
||||
|
||||
return StructureIsReused.Completely;
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@ export interface ResolutionWithFailedLookupLocations {
|
||||
refCount?: number;
|
||||
// Files that have this resolution using
|
||||
files?: Set<Path>;
|
||||
node10Result?: string;
|
||||
}
|
||||
|
||||
interface ResolutionWithResolvedFileName {
|
||||
@@ -956,43 +957,48 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
(resolution.files ??= new Set()).add(filePath);
|
||||
}
|
||||
|
||||
function watchFailedLookupLocation(failedLookupLocation: string, setAtRoot: boolean) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const toWatch = getDirectoryToWatchFailedLookupLocation(
|
||||
failedLookupLocation,
|
||||
failedLookupLocationPath,
|
||||
rootDir,
|
||||
rootPath,
|
||||
rootPathComponents,
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dir, dirPath, nonRecursive } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
Debug.assert(nonRecursive);
|
||||
setAtRoot = true;
|
||||
}
|
||||
else {
|
||||
setDirectoryWatcher(dir, dirPath, nonRecursive);
|
||||
}
|
||||
}
|
||||
return setAtRoot;
|
||||
}
|
||||
|
||||
function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
Debug.assert(!!resolution.refCount);
|
||||
|
||||
const { failedLookupLocations, affectingLocations } = resolution;
|
||||
if (!failedLookupLocations?.length && !affectingLocations?.length) return;
|
||||
if (failedLookupLocations?.length) resolutionsWithFailedLookups.add(resolution);
|
||||
const { failedLookupLocations, affectingLocations, node10Result } = resolution;
|
||||
if (!failedLookupLocations?.length && !affectingLocations?.length && !node10Result) return;
|
||||
if (failedLookupLocations?.length || node10Result) resolutionsWithFailedLookups.add(resolution);
|
||||
|
||||
let setAtRoot = false;
|
||||
if (failedLookupLocations) {
|
||||
for (const failedLookupLocation of failedLookupLocations) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const toWatch = getDirectoryToWatchFailedLookupLocation(
|
||||
failedLookupLocation,
|
||||
failedLookupLocationPath,
|
||||
rootDir,
|
||||
rootPath,
|
||||
rootPathComponents,
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dir, dirPath, nonRecursive } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
Debug.assert(nonRecursive);
|
||||
setAtRoot = true;
|
||||
}
|
||||
else {
|
||||
setDirectoryWatcher(dir, dirPath, nonRecursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setAtRoot) {
|
||||
// This is always non recursive
|
||||
setDirectoryWatcher(rootDir, rootPath, /*nonRecursive*/ true); // TODO: GH#18217
|
||||
setAtRoot = watchFailedLookupLocation(failedLookupLocation, setAtRoot);
|
||||
}
|
||||
}
|
||||
watchAffectingLocationsOfResolution(resolution, !failedLookupLocations?.length);
|
||||
if (node10Result) setAtRoot = watchFailedLookupLocation(node10Result, setAtRoot);
|
||||
if (setAtRoot) {
|
||||
// This is always non recursive
|
||||
setDirectoryWatcher(rootDir, rootPath, /*nonRecursive*/ true);
|
||||
}
|
||||
watchAffectingLocationsOfResolution(resolution, !failedLookupLocations?.length && !node10Result);
|
||||
}
|
||||
|
||||
function watchAffectingLocationsOfResolution(resolution: ResolutionWithFailedLookupLocations, addToResolutionsWithOnlyAffectingLocations: boolean) {
|
||||
@@ -1080,6 +1086,28 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
}
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocation(failedLookupLocation: string, removeAtRoot: boolean) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const toWatch = getDirectoryToWatchFailedLookupLocation(
|
||||
failedLookupLocation,
|
||||
failedLookupLocationPath,
|
||||
rootDir,
|
||||
rootPath,
|
||||
rootPathComponents,
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dirPath } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
removeAtRoot = true;
|
||||
}
|
||||
else {
|
||||
removeDirectoryWatcher(dirPath);
|
||||
}
|
||||
}
|
||||
return removeAtRoot;
|
||||
}
|
||||
|
||||
function stopWatchFailedLookupLocationOfResolution<T extends ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName>(
|
||||
resolution: T,
|
||||
filePath: Path,
|
||||
@@ -1097,32 +1125,16 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
if (resolutions?.delete(resolution) && !resolutions.size) resolvedFileToResolution.delete(key);
|
||||
}
|
||||
|
||||
const { failedLookupLocations, affectingLocations } = resolution;
|
||||
const { failedLookupLocations, affectingLocations, node10Result } = resolution;
|
||||
if (resolutionsWithFailedLookups.delete(resolution)) {
|
||||
let removeAtRoot = false;
|
||||
for (const failedLookupLocation of failedLookupLocations!) {
|
||||
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
|
||||
const toWatch = getDirectoryToWatchFailedLookupLocation(
|
||||
failedLookupLocation,
|
||||
failedLookupLocationPath,
|
||||
rootDir,
|
||||
rootPath,
|
||||
rootPathComponents,
|
||||
getCurrentDirectory,
|
||||
);
|
||||
if (toWatch) {
|
||||
const { dirPath } = toWatch;
|
||||
if (dirPath === rootPath) {
|
||||
removeAtRoot = true;
|
||||
}
|
||||
else {
|
||||
removeDirectoryWatcher(dirPath);
|
||||
}
|
||||
if (failedLookupLocations) {
|
||||
for (const failedLookupLocation of failedLookupLocations) {
|
||||
removeAtRoot = stopWatchFailedLookupLocation(failedLookupLocation, removeAtRoot);
|
||||
}
|
||||
}
|
||||
if (removeAtRoot) {
|
||||
removeDirectoryWatcher(rootPath);
|
||||
}
|
||||
if (node10Result) removeAtRoot = stopWatchFailedLookupLocation(node10Result, removeAtRoot);
|
||||
if (removeAtRoot) removeDirectoryWatcher(rootPath);
|
||||
}
|
||||
else if (affectingLocations?.length) {
|
||||
resolutionsWithOnlyAffectingLocations.delete(resolution);
|
||||
@@ -1313,7 +1325,8 @@ export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootD
|
||||
function canInvalidateFailedLookupResolution(resolution: ResolutionWithFailedLookupLocations) {
|
||||
if (canInvalidatedFailedLookupResolutionWithAffectingLocation(resolution)) return true;
|
||||
if (!failedLookupChecks && !startsWithPathChecks && !isInDirectoryChecks) return false;
|
||||
return resolution.failedLookupLocations?.some(location => isInvalidatedFailedLookup(resolutionHost.toPath(location)));
|
||||
return resolution.failedLookupLocations?.some(location => isInvalidatedFailedLookup(resolutionHost.toPath(location))) ||
|
||||
(!!resolution.node10Result && isInvalidatedFailedLookup(resolutionHost.toPath(resolution.node10Result)));
|
||||
}
|
||||
|
||||
function isInvalidatedFailedLookup(locationPath: Path) {
|
||||
|
||||
@@ -4815,6 +4815,7 @@ export interface Program extends ScriptReferenceHost {
|
||||
* @internal
|
||||
*/
|
||||
resolvedLibReferences: Map<string, LibResolution> | undefined;
|
||||
/** @internal */ getCurrentPackagesMap(): Map<string, boolean> | undefined;
|
||||
/**
|
||||
* Is the file emitted file
|
||||
*
|
||||
@@ -4950,6 +4951,9 @@ export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
|
||||
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
|
||||
|
||||
readonly redirectTargetsMap: RedirectTargetsMap;
|
||||
|
||||
typesPackageExists(packageName: string): boolean;
|
||||
packageBundlesTypes(packageName: string): boolean;
|
||||
}
|
||||
|
||||
export interface TypeChecker {
|
||||
@@ -6923,6 +6927,16 @@ export interface DiagnosticMessage {
|
||||
elidedInCompatabilityPyramid?: boolean;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface RepopulateModuleNotFoundDiagnosticChain {
|
||||
moduleReference: string;
|
||||
mode: ResolutionMode;
|
||||
packageName: string | undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type RepopulateDiagnosticChainInfo = RepopulateModuleNotFoundDiagnosticChain;
|
||||
|
||||
/**
|
||||
* A linked list of formatted diagnostic messages to be used as part of a multiline message.
|
||||
* It is built from the bottom up, leaving the head to be the "main" diagnostic.
|
||||
@@ -6934,6 +6948,8 @@ export interface DiagnosticMessageChain {
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
next?: DiagnosticMessageChain[];
|
||||
/** @internal */
|
||||
repopulateInfo?: () => RepopulateDiagnosticChainInfo;
|
||||
}
|
||||
|
||||
export interface Diagnostic extends DiagnosticRelatedInformation {
|
||||
|
||||
@@ -379,6 +379,7 @@ import {
|
||||
LiteralLikeNode,
|
||||
LogicalOperator,
|
||||
LogicalOrCoalescingAssignmentOperator,
|
||||
mangleScopedPackageName,
|
||||
map,
|
||||
mapDefined,
|
||||
MapLike,
|
||||
@@ -526,6 +527,7 @@ import {
|
||||
TypeAliasDeclaration,
|
||||
TypeAssertion,
|
||||
TypeChecker,
|
||||
TypeCheckerHost,
|
||||
TypeElement,
|
||||
TypeFlags,
|
||||
TypeLiteralNode,
|
||||
@@ -781,7 +783,37 @@ export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleWithFaile
|
||||
oldResolution.resolvedModule.extension === newResolution.resolvedModule.extension &&
|
||||
oldResolution.resolvedModule.resolvedFileName === newResolution.resolvedModule.resolvedFileName &&
|
||||
oldResolution.resolvedModule.originalPath === newResolution.resolvedModule.originalPath &&
|
||||
packageIdIsEqual(oldResolution.resolvedModule.packageId, newResolution.resolvedModule.packageId);
|
||||
packageIdIsEqual(oldResolution.resolvedModule.packageId, newResolution.resolvedModule.packageId) &&
|
||||
oldResolution.node10Result === newResolution.node10Result;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createModuleNotFoundChain(sourceFile: SourceFile, host: TypeCheckerHost, moduleReference: string, mode: ResolutionMode, packageName: string) {
|
||||
const node10Result = sourceFile.resolvedModules?.get(moduleReference, mode)?.node10Result;
|
||||
const result = node10Result
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.There_are_types_at_0_but_this_result_could_not_be_resolved_when_respecting_package_json_exports_The_1_library_may_need_to_update_its_package_json_or_typings,
|
||||
node10Result,
|
||||
node10Result.indexOf(nodeModulesPathPart + "@types/") > -1 ? `@types/${mangleScopedPackageName(packageName)}` : packageName)
|
||||
: host.typesPackageExists(packageName)
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_Slash_Slashgithub_com_SlashDefinitelyTyped_SlashDefinitelyTyped_Slashtree_Slashmaster_Slashtypes_Slash_1,
|
||||
packageName, mangleScopedPackageName(packageName))
|
||||
: host.packageBundlesTypes(packageName)
|
||||
? chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.If_the_0_package_actually_exposes_this_module_try_adding_a_new_declaration_d_ts_file_containing_declare_module_1,
|
||||
packageName,
|
||||
moduleReference)
|
||||
: chainDiagnosticMessages(
|
||||
/*details*/ undefined,
|
||||
Diagnostics.Try_npm_i_save_dev_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0,
|
||||
moduleReference,
|
||||
mangleScopedPackageName(packageName));
|
||||
if (result) result.repopulateInfo = () => ({ moduleReference, mode, packageName: packageName === moduleReference ? undefined : packageName });
|
||||
return result;
|
||||
}
|
||||
|
||||
function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean {
|
||||
|
||||
@@ -110,6 +110,7 @@ import "./unittests/tsc/forceConsistentCasingInFileNames";
|
||||
import "./unittests/tsc/incremental";
|
||||
import "./unittests/tsc/libraryResolution";
|
||||
import "./unittests/tsc/listFilesOnly";
|
||||
import "./unittests/tsc/moduleResolution";
|
||||
import "./unittests/tsc/projectReferences";
|
||||
import "./unittests/tsc/projectReferencesConfig";
|
||||
import "./unittests/tsc/redirect";
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { dedent } from "../../_namespaces/Utils";
|
||||
import { FsContents } from "./contents";
|
||||
import { libFile } from "./virtualFileSystemWithWatch";
|
||||
|
||||
export function getFsConentsForNode10ResultAtTypesPackageJson(packageName: string, addTypesCondition: boolean) {
|
||||
return JSON.stringify({
|
||||
name: `@types/${packageName}`,
|
||||
version: "1.0.0",
|
||||
types: "index.d.ts",
|
||||
exports: {
|
||||
".": {
|
||||
...(addTypesCondition ? { types: "./index.d.ts" } : {}),
|
||||
require: "./index.d.ts"
|
||||
}
|
||||
}
|
||||
}, undefined, " ");
|
||||
}
|
||||
|
||||
export function getFsContentsForNode10ResultPackageJson(packageName: string, addTypes: boolean, addTypesCondition: boolean) {
|
||||
return JSON.stringify({
|
||||
name: packageName,
|
||||
version: "1.0.0",
|
||||
main: "index.js",
|
||||
...(addTypes ? { types: "index.d.ts" } : {}),
|
||||
exports: {
|
||||
".": {
|
||||
...(addTypesCondition ? { types: "./index.d.ts" } : {}),
|
||||
import: "./index.mjs",
|
||||
require: "./index.js"
|
||||
}
|
||||
}
|
||||
}, undefined, " ");
|
||||
}
|
||||
|
||||
export function getFsContentsForNode10ResultDts(packageName: string) {
|
||||
return `export declare const ${packageName}: number;`;
|
||||
}
|
||||
|
||||
function js(packageName: string) {
|
||||
return `module.exports = { ${packageName}: 1 };`;
|
||||
}
|
||||
|
||||
function mjs(packageName: string) {
|
||||
return `export const ${packageName} = 1;`;
|
||||
}
|
||||
|
||||
export function getFsContentsForNode10Result(): FsContents {
|
||||
return {
|
||||
"/home/src/projects/project/node_modules/@types/bar/package.json": getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ false),
|
||||
"/home/src/projects/project/node_modules/@types/bar/index.d.ts": getFsContentsForNode10ResultDts("bar"),
|
||||
"/home/src/projects/project/node_modules/bar/package.json": getFsContentsForNode10ResultPackageJson("bar", /*addTypes*/ false, /*addTypesCondition*/ false),
|
||||
"/home/src/projects/project/node_modules/bar/index.js": js("bar"),
|
||||
"/home/src/projects/project/node_modules/bar/index.mjs": mjs("bar"),
|
||||
"/home/src/projects/project/node_modules/foo/package.json": getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ false),
|
||||
"/home/src/projects/project/node_modules/foo/index.js": js("foo"),
|
||||
"/home/src/projects/project/node_modules/foo/index.mjs": mjs("foo"),
|
||||
"/home/src/projects/project/node_modules/foo/index.d.ts": getFsContentsForNode10ResultDts("foo"),
|
||||
"/home/src/projects/project/node_modules/@types/bar2/package.json": getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ true),
|
||||
"/home/src/projects/project/node_modules/@types/bar2/index.d.ts": getFsContentsForNode10ResultDts("bar2"),
|
||||
"/home/src/projects/project/node_modules/bar2/package.json": getFsContentsForNode10ResultPackageJson("bar2", /*addTypes*/ false, /*addTypesCondition*/ false),
|
||||
"/home/src/projects/project/node_modules/bar2/index.js": js("bar2"),
|
||||
"/home/src/projects/project/node_modules/bar2/index.mjs": mjs("bar2"),
|
||||
"/home/src/projects/project/node_modules/foo2/package.json": getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ true),
|
||||
"/home/src/projects/project/node_modules/foo2/index.js": js("foo2"),
|
||||
"/home/src/projects/project/node_modules/foo2/index.mjs": mjs("foo2"),
|
||||
"/home/src/projects/project/node_modules/foo2/index.d.ts": getFsContentsForNode10ResultDts("foo2"),
|
||||
"/home/src/projects/project/index.mts": dedent`
|
||||
import { foo } from "foo";
|
||||
import { bar } from "bar";
|
||||
import { foo2 } from "foo2";
|
||||
import { bar2 } from "bar2";
|
||||
`,
|
||||
"/home/src/projects/project/tsconfig.json": JSON.stringify({
|
||||
compilerOptions: {
|
||||
moduleResolution: "node16",
|
||||
traceResolution: true,
|
||||
incremental: true,
|
||||
strict: true,
|
||||
types: [],
|
||||
},
|
||||
files: ["index.mts"]
|
||||
}),
|
||||
[libFile.path]: libFile.content,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result";
|
||||
import { verifyTsc } from "../helpers/tsc";
|
||||
import { loadProjectFromFiles } from "../helpers/vfs";
|
||||
|
||||
describe("unittests:: tsc:: moduleResolution::", () => {
|
||||
verifyTsc({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "node10Result",
|
||||
fs: () => loadProjectFromFiles(getFsContentsForNode10Result()),
|
||||
commandLineArgs: ["-p", "/home/src/projects/project"],
|
||||
baselinePrograms: true,
|
||||
edits: [
|
||||
{
|
||||
caption: "delete the node10Result in @types",
|
||||
edit: fs => fs.unlinkSync("/home/src/projects/project/node_modules/@types/bar/index.d.ts"),
|
||||
},
|
||||
{
|
||||
caption: "delete the ndoe10Result in package/types",
|
||||
edit: fs => fs.unlinkSync("/home/src/projects/project/node_modules/foo/index.d.ts"),
|
||||
},
|
||||
{
|
||||
caption: "add the node10Result in @types",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar")),
|
||||
},
|
||||
{
|
||||
caption: "add the ndoe10Result in package/types",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo")),
|
||||
},
|
||||
{
|
||||
caption: "update package.json from @types so error is fixed",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true)),
|
||||
},
|
||||
{
|
||||
caption: "update package.json so error is fixed",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true)),
|
||||
},
|
||||
{
|
||||
caption: "update package.json from @types so error is introduced",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false)),
|
||||
},
|
||||
{
|
||||
caption: "update package.json so error is introduced",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false)),
|
||||
},
|
||||
{
|
||||
caption: "delete the node10Result in @types",
|
||||
edit: fs => fs.unlinkSync("/home/src/projects/project/node_modules/@types/bar2/index.d.ts"),
|
||||
},
|
||||
{
|
||||
caption: "delete the ndoe10Result in package/types",
|
||||
edit: fs => fs.unlinkSync("/home/src/projects/project/node_modules/foo2/index.d.ts"),
|
||||
},
|
||||
{
|
||||
caption: "add the node10Result in @types",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2")),
|
||||
},
|
||||
{
|
||||
caption: "add the ndoe10Result in package/types",
|
||||
edit: fs => fs.writeFileSync("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2")),
|
||||
},
|
||||
]
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result";
|
||||
import { verifyTscWatch } from "../helpers/tscWatch";
|
||||
import {
|
||||
createWatchedSystem,
|
||||
@@ -432,4 +433,109 @@ describe("unittests:: tsc-watch:: moduleResolution", () => {
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
verifyTscWatch({
|
||||
scenario: "moduleResolution",
|
||||
subScenario: "node10Result",
|
||||
sys: () => createWatchedSystem(getFsContentsForNode10Result(), { currentDirectory: "/home/src/projects/project" }),
|
||||
commandLineArgs: ["-w", "--extendedDiagnostics"],
|
||||
edits: [
|
||||
{
|
||||
caption: "delete the node10Result in @types",
|
||||
edit: sys => sys.deleteFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts"),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "delete the ndoe10Result in package/types",
|
||||
edit: sys => sys.deleteFile("/home/src/projects/project/node_modules/foo/index.d.ts"),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "add the node10Result in @types",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar")),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "add the ndoe10Result in package/types",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo")),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "update package.json from @types so error is fixed",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true)),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "update package.json so error is fixed",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true)),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "update package.json from @types so error is introduced",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false)),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "update package.json so error is introduced",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false)),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "delete the node10Result in @types",
|
||||
edit: sys => sys.deleteFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts"),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "delete the ndoe10Result in package/types",
|
||||
edit: sys => sys.deleteFile("/home/src/projects/project/node_modules/foo2/index.d.ts"),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "add the node10Result in @types",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2")),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
{
|
||||
caption: "add the ndoe10Result in package/types",
|
||||
edit: sys => sys.writeFile("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2")),
|
||||
timeouts: sys => {
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
sys.runQueuedTimeoutCallbacks();
|
||||
},
|
||||
},
|
||||
]
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Utils from "../../_namespaces/Utils";
|
||||
import { getFsConentsForNode10ResultAtTypesPackageJson, getFsContentsForNode10Result, getFsContentsForNode10ResultDts, getFsContentsForNode10ResultPackageJson } from "../helpers/node10Result";
|
||||
import {
|
||||
baselineTsserverLogs,
|
||||
createLoggerWithInMemoryLogs,
|
||||
@@ -130,4 +131,49 @@ describe("unittests:: tsserver:: moduleResolution", () => {
|
||||
baselineTsserverLogs("moduleResolution", "package json file is edited when package json with type module exists", session);
|
||||
});
|
||||
});
|
||||
|
||||
it("node10Result", () => {
|
||||
const host = createServerHost(getFsContentsForNode10Result());
|
||||
const session = createSession(host, { canUseEvents: true, logger: createLoggerWithInMemoryLogs(host) });
|
||||
openFilesForSession(["/home/src/projects/project/index.mts"], session);
|
||||
verifyGetErrRequest({
|
||||
files: ["/home/src/projects/project/index.mts"],
|
||||
session,
|
||||
});
|
||||
host.deleteFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts");
|
||||
verifyErrors();
|
||||
host.deleteFile("/home/src/projects/project/node_modules/foo/index.d.ts");
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/@types/bar/index.d.ts", getFsContentsForNode10ResultDts("bar"));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/foo/index.d.ts", getFsContentsForNode10ResultDts("foo"));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/@types/bar/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar", /*addTypesCondition*/ true));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/foo/package.json", getFsContentsForNode10ResultPackageJson("foo", /*addTypes*/ true, /*addTypesCondition*/ true));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/@types/bar2/package.json", getFsConentsForNode10ResultAtTypesPackageJson("bar2", /*addTypesCondition*/ false));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/foo2/package.json", getFsContentsForNode10ResultPackageJson("foo2", /*addTypes*/ true, /*addTypesCondition*/ false));
|
||||
verifyErrors();
|
||||
host.deleteFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts");
|
||||
verifyErrors();
|
||||
host.deleteFile("/home/src/projects/project/node_modules/foo2/index.d.ts");
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/@types/bar2/index.d.ts", getFsContentsForNode10ResultDts("bar2"));
|
||||
verifyErrors();
|
||||
host.writeFile("/home/src/projects/project/node_modules/foo2/index.d.ts", getFsContentsForNode10ResultDts("foo2"));
|
||||
verifyErrors();
|
||||
|
||||
baselineTsserverLogs("moduleResolution", "node10Result", session);
|
||||
|
||||
function verifyErrors() {
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
host.runQueuedImmediateCallbacks();
|
||||
verifyGetErrRequest({
|
||||
files: ["/home/src/projects/project/index.mts"],
|
||||
session,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user