mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
Always update LS state through Project (#56356)
Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
parent
80ab111685
commit
ca7a3af5e6
@ -1330,6 +1330,14 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
this.hasAddedOrRemovedSymlinks = true;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
updateFromProjectInProgress = false;
|
||||
|
||||
/** @internal */
|
||||
updateFromProject() {
|
||||
updateProjectIfDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates set of files that contribute to this project
|
||||
* @returns: true if set of files in the project stays the same and false - otherwise.
|
||||
@ -1523,8 +1531,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
|
||||
this.hasInvalidatedResolutions = hasInvalidatedResolutions;
|
||||
this.hasInvalidatedLibResolutions = hasInvalidatedLibResolutions;
|
||||
this.resolutionCache.startCachingPerDirectoryResolution();
|
||||
this.program = this.languageService.getProgram(); // TODO: GH#18217
|
||||
this.dirty = false;
|
||||
this.updateFromProjectInProgress = true;
|
||||
this.program = this.languageService.getProgram(); // TODO: GH#18217
|
||||
this.updateFromProjectInProgress = false;
|
||||
tracing?.push(tracing.Phase.Session, "finishCachingPerDirectoryResolution");
|
||||
this.resolutionCache.finishCachingPerDirectoryResolution(this.program, oldProgram);
|
||||
tracing?.pop();
|
||||
|
||||
@ -1620,6 +1620,15 @@ export function createLanguageService(
|
||||
}
|
||||
|
||||
function synchronizeHostData(): void {
|
||||
if (host.updateFromProject && !host.updateFromProjectInProgress) {
|
||||
host.updateFromProject();
|
||||
}
|
||||
else {
|
||||
synchronizeHostDataWorker();
|
||||
}
|
||||
}
|
||||
|
||||
function synchronizeHostDataWorker(): void {
|
||||
Debug.assert(languageServiceMode !== LanguageServiceMode.Syntactic);
|
||||
// perform fast check if host supports it
|
||||
if (host.getProjectVersion) {
|
||||
|
||||
@ -316,6 +316,9 @@ export interface IncompleteCompletionsCache {
|
||||
export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalResolutionCacheHost {
|
||||
getCompilationSettings(): CompilerOptions;
|
||||
getNewLine?(): string;
|
||||
/** @internal */ updateFromProject?(): void;
|
||||
/** @internal */ updateFromProjectInProgress?: boolean;
|
||||
|
||||
getProjectVersion?(): string;
|
||||
getScriptFileNames(): string[];
|
||||
getScriptKind?(fileName: string): ScriptKind;
|
||||
|
||||
@ -28,6 +28,8 @@ describe("unittests:: tsserver:: plugins:: loading", () => {
|
||||
create(info: ts.server.PluginCreateInfo) {
|
||||
info.session?.addProtocolHandler(testProtocolCommand, request => {
|
||||
session.logger.log(`addProtocolHandler: ${jsonToReadableText(request)}`);
|
||||
// Assume this one needs program
|
||||
info.languageService.getProgram();
|
||||
return {
|
||||
response: testProtocolCommandResponse,
|
||||
};
|
||||
@ -101,6 +103,41 @@ describe("unittests:: tsserver:: plugins:: loading", () => {
|
||||
baselineTsserverLogs("plugins", "With session and custom protocol message", session);
|
||||
});
|
||||
|
||||
it("when plugins use LS to get program and update is pending", () => {
|
||||
const pluginName = "some-plugin";
|
||||
const aTs: File = {
|
||||
path: "/user/username/projects/project/a.ts",
|
||||
content: `/// <reference path="./b.ts"/>`,
|
||||
};
|
||||
const tsconfig: File = {
|
||||
path: "/user/username/projects/project/tsconfig.json",
|
||||
content: jsonToReadableText({
|
||||
compilerOptions: {
|
||||
plugins: [
|
||||
{ name: pluginName },
|
||||
],
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const { session, host } = createHostWithPlugin([aTs, tsconfig, libFile]);
|
||||
|
||||
openFilesForSession([aTs], session);
|
||||
// Write the missing file (referenced by 'a.ts') to schedule an update.
|
||||
host.writeFile("/user/username/projects/project/b.ts", "const y = 10;");
|
||||
|
||||
// This should update the language service with a new program.
|
||||
session.executeCommandSeq({
|
||||
command: testProtocolCommand,
|
||||
arguments: testProtocolCommandRequest,
|
||||
});
|
||||
|
||||
// This results in a program update.
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
|
||||
baselineTsserverLogs("plugins", "when plugins use LS to get program and update is pending", session);
|
||||
});
|
||||
|
||||
it("gets external files with config file reload", () => {
|
||||
const aTs: File = { path: `/user/username/projects/myproject/a.ts`, content: `export const x = 10;` };
|
||||
const tsconfig: File = {
|
||||
|
||||
@ -0,0 +1,318 @@
|
||||
currentDirectory:: / useCaseSensitiveFileNames: false
|
||||
Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist
|
||||
Before request
|
||||
//// [/user/username/projects/project/a.ts]
|
||||
/// <reference path="./b.ts"/>
|
||||
|
||||
//// [/user/username/projects/project/tsconfig.json]
|
||||
{
|
||||
"compilerOptions": {
|
||||
"plugins": [
|
||||
{
|
||||
"name": "some-plugin"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
//// [/a/lib/lib.d.ts]
|
||||
/// <reference no-default-lib="true"/>
|
||||
interface Boolean {}
|
||||
interface Function {}
|
||||
interface CallableFunction {}
|
||||
interface NewableFunction {}
|
||||
interface IArguments {}
|
||||
interface Number { toExponential: any; }
|
||||
interface Object {}
|
||||
interface RegExp {}
|
||||
interface String { charAt: any; }
|
||||
interface Array<T> { length: number; [n: number]: T; }
|
||||
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "open",
|
||||
"arguments": {
|
||||
"file": "/user/username/projects/project/a.ts"
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Search path: /user/username/projects/project
|
||||
Info seq [hh:mm:ss:mss] For info: /user/username/projects/project/a.ts :: Config file name: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Creating configuration project /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/project/tsconfig.json 2000 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Config file
|
||||
Info seq [hh:mm:ss:mss] event:
|
||||
{
|
||||
"seq": 0,
|
||||
"type": "event",
|
||||
"event": "projectLoadingStart",
|
||||
"body": {
|
||||
"projectName": "/user/username/projects/project/tsconfig.json",
|
||||
"reason": "Creating possible configured project for /user/username/projects/project/a.ts to open"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Config: /user/username/projects/project/tsconfig.json : {
|
||||
"rootNames": [
|
||||
"/user/username/projects/project/a.ts"
|
||||
],
|
||||
"options": {
|
||||
"plugins": [
|
||||
{
|
||||
"name": "some-plugin"
|
||||
}
|
||||
],
|
||||
"configFilePath": "/user/username/projects/project/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/project 1 undefined Config: /user/username/projects/project/tsconfig.json WatchType: Wild card directory
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/project 1 undefined Config: /user/username/projects/project/tsconfig.json WatchType: Wild card directory
|
||||
Info seq [hh:mm:ss:mss] Enabling plugin some-plugin from candidate paths: /a/lib/tsc.js/../../..
|
||||
Info seq [hh:mm:ss:mss] Loading some-plugin from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules)
|
||||
Loading plugin: some-plugin
|
||||
Info seq [hh:mm:ss:mss] Plugin validation succeeded
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/project/b.ts 500 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/project/node_modules/@types 1 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Type roots
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/project/node_modules/@types 1 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Type roots
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/node_modules/@types 1 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Type roots
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/node_modules/@types 1 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Type roots
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /user/username/projects/project/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/user/username/projects/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (2)
|
||||
/a/lib/lib.d.ts Text-1 "/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }"
|
||||
/user/username/projects/project/a.ts SVC-1-0 "/// <reference path=\"./b.ts\"/>"
|
||||
|
||||
|
||||
../../../../a/lib/lib.d.ts
|
||||
Default library for target 'es5'
|
||||
a.ts
|
||||
Matched by default include pattern '**/*'
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] event:
|
||||
{
|
||||
"seq": 0,
|
||||
"type": "event",
|
||||
"event": "projectLoadingFinish",
|
||||
"body": {
|
||||
"projectName": "/user/username/projects/project/tsconfig.json"
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] event:
|
||||
{
|
||||
"seq": 0,
|
||||
"type": "event",
|
||||
"event": "telemetry",
|
||||
"body": {
|
||||
"telemetryEventName": "projectInfo",
|
||||
"payload": {
|
||||
"projectId": "ff5803d884ff4e4485901596e00c181622d4efba4fec19a41fe48adf94ccdf94",
|
||||
"fileStats": {
|
||||
"js": 0,
|
||||
"jsSize": 0,
|
||||
"jsx": 0,
|
||||
"jsxSize": 0,
|
||||
"ts": 1,
|
||||
"tsSize": 30,
|
||||
"tsx": 0,
|
||||
"tsxSize": 0,
|
||||
"dts": 1,
|
||||
"dtsSize": 334,
|
||||
"deferred": 0,
|
||||
"deferredSize": 0
|
||||
},
|
||||
"compilerOptions": {
|
||||
"plugins": [
|
||||
""
|
||||
]
|
||||
},
|
||||
"typeAcquisition": {
|
||||
"enable": false,
|
||||
"include": false,
|
||||
"exclude": false
|
||||
},
|
||||
"extends": false,
|
||||
"files": false,
|
||||
"include": false,
|
||||
"exclude": false,
|
||||
"compileOnSave": false,
|
||||
"configFileName": "tsconfig.json",
|
||||
"projectType": "configured",
|
||||
"languageServiceEnabled": true,
|
||||
"version": "FakeVersion"
|
||||
}
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] event:
|
||||
{
|
||||
"seq": 0,
|
||||
"type": "event",
|
||||
"event": "configFileDiag",
|
||||
"body": {
|
||||
"triggerFile": "/user/username/projects/project/a.ts",
|
||||
"configFile": "/user/username/projects/project/tsconfig.json",
|
||||
"diagnostics": []
|
||||
}
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] Project '/user/username/projects/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (2)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/project/a.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"responseRequired": false
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/user/username/projects/node_modules/@types: *new*
|
||||
{"pollingInterval":500}
|
||||
/user/username/projects/project/b.ts: *new*
|
||||
{"pollingInterval":500}
|
||||
/user/username/projects/project/node_modules/@types: *new*
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/a/lib/lib.d.ts: *new*
|
||||
{}
|
||||
/user/username/projects/project/tsconfig.json: *new*
|
||||
{}
|
||||
|
||||
FsWatchesRecursive::
|
||||
/user/username/projects/project: *new*
|
||||
{}
|
||||
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Triggered with /user/username/projects/project/b.ts 0:: WatchInfo: /user/username/projects/project/b.ts 500 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /user/username/projects/project/b.ts 500 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] Scheduled: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Scheduled: *ensureProjectForOpenFiles*
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms FileWatcher:: Triggered with /user/username/projects/project/b.ts 0:: WatchInfo: /user/username/projects/project/b.ts 500 undefined Project: /user/username/projects/project/tsconfig.json WatchType: Missing file
|
||||
Info seq [hh:mm:ss:mss] DirectoryWatcher:: Triggered with /user/username/projects/project/b.ts :: WatchInfo: /user/username/projects/project 1 undefined Config: /user/username/projects/project/tsconfig.json WatchType: Wild card directory
|
||||
Info seq [hh:mm:ss:mss] Scheduled: /user/username/projects/project/tsconfig.json, Cancelled earlier one
|
||||
Info seq [hh:mm:ss:mss] Scheduled: *ensureProjectForOpenFiles*, Cancelled earlier one
|
||||
Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Triggered with /user/username/projects/project/b.ts :: WatchInfo: /user/username/projects/project 1 undefined Config: /user/username/projects/project/tsconfig.json WatchType: Wild card directory
|
||||
Before request
|
||||
//// [/user/username/projects/project/b.ts]
|
||||
const y = 10;
|
||||
|
||||
|
||||
PolledWatches::
|
||||
/user/username/projects/node_modules/@types:
|
||||
{"pollingInterval":500}
|
||||
/user/username/projects/project/node_modules/@types:
|
||||
{"pollingInterval":500}
|
||||
|
||||
PolledWatches *deleted*::
|
||||
/user/username/projects/project/b.ts:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{}
|
||||
/user/username/projects/project/tsconfig.json:
|
||||
{}
|
||||
|
||||
FsWatchesRecursive::
|
||||
/user/username/projects/project:
|
||||
{}
|
||||
|
||||
Timeout callback:: count: 2
|
||||
3: /user/username/projects/project/tsconfig.json *new*
|
||||
4: *ensureProjectForOpenFiles* *new*
|
||||
|
||||
Info seq [hh:mm:ss:mss] request:
|
||||
{
|
||||
"command": "testProtocolCommand",
|
||||
"arguments": "testProtocolCommandRequest",
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
addProtocolHandler: {
|
||||
"command": "testProtocolCommand",
|
||||
"arguments": "testProtocolCommandRequest",
|
||||
"seq": 2,
|
||||
"type": "request"
|
||||
}
|
||||
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /user/username/projects/project/b.ts 500 undefined WatchType: Closed Script info
|
||||
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /user/username/projects/project/tsconfig.json Version: 2 structureChanged: true structureIsReused:: Not Elapsed:: *ms
|
||||
Info seq [hh:mm:ss:mss] Project '/user/username/projects/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (3)
|
||||
/a/lib/lib.d.ts Text-1 "/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }"
|
||||
/user/username/projects/project/b.ts Text-1 "const y = 10;"
|
||||
/user/username/projects/project/a.ts SVC-1-0 "/// <reference path=\"./b.ts\"/>"
|
||||
|
||||
|
||||
../../../../a/lib/lib.d.ts
|
||||
Default library for target 'es5'
|
||||
b.ts
|
||||
Referenced via './b.ts' from file 'a.ts'
|
||||
Matched by default include pattern '**/*'
|
||||
a.ts
|
||||
Matched by default include pattern '**/*'
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] response:
|
||||
{
|
||||
"response": "testProtocolCommandResponse"
|
||||
}
|
||||
After request
|
||||
|
||||
PolledWatches::
|
||||
/user/username/projects/node_modules/@types:
|
||||
{"pollingInterval":500}
|
||||
/user/username/projects/project/node_modules/@types:
|
||||
{"pollingInterval":500}
|
||||
|
||||
FsWatches::
|
||||
/a/lib/lib.d.ts:
|
||||
{}
|
||||
/user/username/projects/project/b.ts: *new*
|
||||
{}
|
||||
/user/username/projects/project/tsconfig.json:
|
||||
{}
|
||||
|
||||
FsWatchesRecursive::
|
||||
/user/username/projects/project:
|
||||
{}
|
||||
|
||||
Before running Timeout callback:: count: 2
|
||||
3: /user/username/projects/project/tsconfig.json
|
||||
4: *ensureProjectForOpenFiles*
|
||||
|
||||
Info seq [hh:mm:ss:mss] Running: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] Running: *ensureProjectForOpenFiles*
|
||||
Info seq [hh:mm:ss:mss] Before ensureProjectForOpenFiles:
|
||||
Info seq [hh:mm:ss:mss] Project '/user/username/projects/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (3)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/project/a.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] After ensureProjectForOpenFiles:
|
||||
Info seq [hh:mm:ss:mss] Project '/user/username/projects/project/tsconfig.json' (Configured)
|
||||
Info seq [hh:mm:ss:mss] Files (3)
|
||||
|
||||
Info seq [hh:mm:ss:mss] -----------------------------------------------
|
||||
Info seq [hh:mm:ss:mss] Open files:
|
||||
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/project/a.ts ProjectRootPath: undefined
|
||||
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/project/tsconfig.json
|
||||
Info seq [hh:mm:ss:mss] got projects updated in background /user/username/projects/project/a.ts
|
||||
Info seq [hh:mm:ss:mss] event:
|
||||
{
|
||||
"seq": 0,
|
||||
"type": "event",
|
||||
"event": "projectsUpdatedInBackground",
|
||||
"body": {
|
||||
"openFiles": [
|
||||
"/user/username/projects/project/a.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
After running Timeout callback:: count: 0
|
||||
Loading…
x
Reference in New Issue
Block a user