Skip to content

Commit a455955

Browse files
authored
Make hasInvalidatedResolution non internal for program and add it watchApi (#50776)
* Make stub for hasInvalidatedResolution * Wire through hasInvalidatedResolutions Fixes #48057 * Update comment * Feedback
1 parent 645d1cd commit a455955

File tree

9 files changed

+656
-29
lines changed

9 files changed

+656
-29
lines changed

src/compiler/resolutionCache.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace ts {
1414
removeResolutionsOfFile(filePath: Path): void;
1515
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
1616
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: ESMap<Path, readonly string[]>): void;
17-
createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution;
17+
createHasInvalidatedResolution(customHasInvalidatedResolution: HasInvalidatedResolution): HasInvalidatedResolution;
1818
hasChangedAutomaticTypeDirectiveNames(): boolean;
1919
isFileWithInvalidatedNonRelativeUnresolvedImports(path: Path): boolean;
2020

@@ -300,17 +300,13 @@ namespace ts {
300300
return !!value && !!value.length;
301301
}
302302

303-
function createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution {
303+
function createHasInvalidatedResolution(customHasInvalidatedResolution: HasInvalidatedResolution): HasInvalidatedResolution {
304304
// Ensure pending resolutions are applied
305305
invalidateResolutionsOfFailedLookupLocations();
306-
if (forceAllFilesAsInvalidated) {
307-
// Any file asked would have invalidated resolution
308-
filesWithInvalidatedResolutions = undefined;
309-
return returnTrue;
310-
}
311306
const collected = filesWithInvalidatedResolutions;
312307
filesWithInvalidatedResolutions = undefined;
313-
return path => (!!collected && collected.has(path)) ||
308+
return path => customHasInvalidatedResolution(path) ||
309+
!!collected?.has(path) ||
314310
isFileWithInvalidatedNonRelativeUnresolvedImports(path);
315311
}
316312

src/compiler/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7215,7 +7215,8 @@ namespace ts {
72157215
getEnvironmentVariable?(name: string): string | undefined;
72167216
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
72177217
/* @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void;
7218-
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
7218+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
7219+
hasInvalidatedResolution?(filePath: Path): boolean;
72197220
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: HasChangedAutomaticTypeDirectiveNames;
72207221
createHash?(data: string): string;
72217222
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;

src/compiler/watchPublic.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ namespace ts {
112112
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[];
113113
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
114114
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[];
115+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
116+
hasInvalidatedResolution?(filePath: Path): boolean;
115117
/**
116118
* Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it
117119
*/
@@ -371,6 +373,10 @@ namespace ts {
371373
maybeBind(host, host.getModuleResolutionCache) :
372374
(() => resolutionCache.getModuleResolutionCache());
373375
const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives;
376+
// All resolutions are invalid if user provided resolutions and didnt supply hasInvalidatedResolution
377+
const customHasInvalidatedResolution = userProvidedResolution ?
378+
maybeBind(host, host.hasInvalidatedResolution) || returnTrue :
379+
returnFalse;
374380

375381
builderProgram = readBuilderProgram(compilerOptions, compilerHost) as any as T;
376382
synchronizeProgram();
@@ -443,8 +449,7 @@ namespace ts {
443449
}
444450
}
445451

446-
// All resolutions are invalid if user provided resolutions
447-
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution);
452+
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(customHasInvalidatedResolution);
448453
const {
449454
originalReadFile, originalFileExists, originalDirectoryExists,
450455
originalCreateDirectory, originalWriteFile,

src/server/project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,7 @@ namespace ts.server {
11761176
Debug.assert(!this.isClosed(), "Called update graph worker of closed project");
11771177
this.writeLog(`Starting updateGraphWorker: Project: ${this.getProjectName()}`);
11781178
const start = timestamp();
1179-
this.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution();
1179+
this.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution(returnFalse);
11801180
this.resolutionCache.startCachingPerDirectoryResolution();
11811181
this.program = this.languageService.getProgram(); // TODO: GH#18217
11821182
this.dirty = false;

src/testRunner/unittests/tscWatch/watchApi.ts

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
namespace ts.tscWatch {
22
describe("unittests:: tsc-watch:: watchAPI:: tsc-watch with custom module resolution", () => {
3-
const configFileJson: any = {
4-
compilerOptions: { module: "commonjs", resolveJsonModule: true },
5-
files: ["index.ts"]
6-
};
7-
const mainFile: File = {
8-
path: `${projectRoot}/index.ts`,
9-
content: "import settings from './settings.json';"
10-
};
11-
const config: File = {
12-
path: `${projectRoot}/tsconfig.json`,
13-
content: JSON.stringify(configFileJson)
14-
};
15-
const settingsJson: File = {
16-
path: `${projectRoot}/settings.json`,
17-
content: JSON.stringify({ content: "Print this" })
18-
};
19-
203
it("verify that module resolution with json extension works when returned without extension", () => {
4+
const configFileJson: any = {
5+
compilerOptions: { module: "commonjs", resolveJsonModule: true },
6+
files: ["index.ts"]
7+
};
8+
const mainFile: File = {
9+
path: `${projectRoot}/index.ts`,
10+
content: "import settings from './settings.json';"
11+
};
12+
const config: File = {
13+
path: `${projectRoot}/tsconfig.json`,
14+
content: JSON.stringify(configFileJson)
15+
};
16+
const settingsJson: File = {
17+
path: `${projectRoot}/settings.json`,
18+
content: JSON.stringify({ content: "Print this" })
19+
};
2120
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem(
2221
[libFile, mainFile, config, settingsJson],
2322
{ currentDirectory: projectRoot }),
@@ -50,6 +49,64 @@ namespace ts.tscWatch {
5049
watchOrSolution: watch
5150
});
5251
});
52+
53+
describe("hasInvalidatedResolution", () => {
54+
function verifyWatch(subScenario: string, implementHasInvalidatedResolution: boolean) {
55+
it(subScenario, () => {
56+
const { sys, baseline, oldSnap, cb, getPrograms } = createBaseline(createWatchedSystem({
57+
[`${projectRoot}/tsconfig.json`]: JSON.stringify({
58+
compilerOptions: { traceResolution: true, extendedDiagnostics: true },
59+
files: ["main.ts"]
60+
}),
61+
[`${projectRoot}/main.ts`]: `import { foo } from "./other";`,
62+
[`${projectRoot}/other.d.ts`]: "export function foo(): void;",
63+
[libFile.path]: libFile.content,
64+
}, { currentDirectory: projectRoot }));
65+
const host = createWatchCompilerHostOfConfigFileForBaseline({
66+
configFileName: `${projectRoot}/tsconfig.json`,
67+
system: sys,
68+
cb,
69+
});
70+
host.resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference, options) =>
71+
moduleNames.map(m => resolveModuleName(m, containingFile, options, host).resolvedModule);
72+
// Invalidate resolutions only when ts file is created
73+
if (implementHasInvalidatedResolution) host.hasInvalidatedResolution = () => sys.fileExists(`${projectRoot}/other.ts`);
74+
const watch = createWatchProgram(host);
75+
runWatchBaseline({
76+
scenario: "watchApi",
77+
subScenario,
78+
commandLineArgs: ["--w"],
79+
sys,
80+
baseline,
81+
oldSnap,
82+
getPrograms,
83+
changes: [
84+
{
85+
caption: "write other with same contents",
86+
change: sys => sys.appendFile(`${projectRoot}/other.d.ts`, ""),
87+
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
88+
},
89+
{
90+
caption: "change other file",
91+
change: sys => sys.appendFile(`${projectRoot}/other.d.ts`, "export function bar(): void;"),
92+
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
93+
},
94+
{
95+
caption: "write other with same contents but write ts file",
96+
change: sys => {
97+
sys.appendFile(`${projectRoot}/other.d.ts`, "");
98+
sys.writeFile(`${projectRoot}/other.ts`, "export function foo() {}");
99+
},
100+
timeouts: sys => sys.runQueuedTimeoutCallbacks(),
101+
},
102+
],
103+
watchOrSolution: watch
104+
});
105+
});
106+
}
107+
verifyWatch("host implements does not implement hasInvalidatedResolution", /*implementHasInvalidatedResolution*/ false);
108+
verifyWatch("host implements hasInvalidatedResolution", /*implementHasInvalidatedResolution*/ true);
109+
});
53110
});
54111

55112
describe("unittests:: tsc-watch:: watchAPI:: tsc-watch expose error count to watch status reporter", () => {

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,6 +3320,8 @@ declare namespace ts {
33203320
*/
33213321
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[];
33223322
getEnvironmentVariable?(name: string): string | undefined;
3323+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
3324+
hasInvalidatedResolution?(filePath: Path): boolean;
33233325
createHash?(data: string): string;
33243326
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
33253327
}
@@ -5442,6 +5444,8 @@ declare namespace ts {
54425444
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[];
54435445
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
54445446
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[];
5447+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
5448+
hasInvalidatedResolution?(filePath: Path): boolean;
54455449
/**
54465450
* Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it
54475451
*/

tests/baselines/reference/api/typescript.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,6 +3320,8 @@ declare namespace ts {
33203320
*/
33213321
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[];
33223322
getEnvironmentVariable?(name: string): string | undefined;
3323+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
3324+
hasInvalidatedResolution?(filePath: Path): boolean;
33233325
createHash?(data: string): string;
33243326
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
33253327
}
@@ -5442,6 +5444,8 @@ declare namespace ts {
54425444
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingSourceFile?: SourceFile): (ResolvedModule | undefined)[];
54435445
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
54445446
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[] | readonly FileReference[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, containingFileMode?: SourceFile["impliedNodeFormat"] | undefined): (ResolvedTypeReferenceDirective | undefined)[];
5447+
/** If provided along with custom resolveModuleNames or resolveTypeReferenceDirectives, used to determine if unchanged file path needs to re-resolve modules/type reference directives */
5448+
hasInvalidatedResolution?(filePath: Path): boolean;
54455449
/**
54465450
* Returns the module resolution cache used by a provided `resolveModuleNames` implementation so that any non-name module resolution operations (eg, package.json lookup) can reuse it
54475451
*/

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy