diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index 77b28720d56fb..d02d93c8bc2ac 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -170,6 +170,7 @@ import "./unittests/tsserver/openFile"; import "./unittests/tsserver/packageJsonInfo"; import "./unittests/tsserver/partialSemanticServer"; import "./unittests/tsserver/plugins"; +import "./unittests/tsserver/pluginsAsync"; import "./unittests/tsserver/projectErrors"; import "./unittests/tsserver/projectReferenceCompileOnSave"; import "./unittests/tsserver/projectReferenceErrors"; diff --git a/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts b/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts index 82a4094f25167..0ab3df9d2ab4e 100644 --- a/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts +++ b/src/testRunner/unittests/helpers/virtualFileSystemWithWatch.ts @@ -292,7 +292,8 @@ export class TestServerHost implements server.ServerHost, FormatDiagnosticsHost, private readonly environmentVariables?: Map; private readonly executingFilePath: string; private readonly currentDirectory: string; - public require: ((initialPath: string, moduleName: string) => ModuleImportResult) | undefined; + require?: (initialPath: string, moduleName: string) => ModuleImportResult; + importPlugin?: (root: string, moduleName: string) => Promise; public storeFilesChangingSignatureDuringEmit = true; watchFile: HostWatchFile; private inodeWatching: boolean | undefined; diff --git a/src/testRunner/unittests/tsserver/pluginsAsync.ts b/src/testRunner/unittests/tsserver/pluginsAsync.ts new file mode 100644 index 0000000000000..1dda2ff6d5dce --- /dev/null +++ b/src/testRunner/unittests/tsserver/pluginsAsync.ts @@ -0,0 +1,177 @@ +import * as ts from "../../_namespaces/ts"; +import { defer } from "../../_namespaces/Utils"; +import { + baselineTsserverLogs, + closeFilesForSession, + createLoggerWithInMemoryLogs, + createSession, + openFilesForSession, +} from "../helpers/tsserver"; +import { createServerHost, libFile } from "../helpers/virtualFileSystemWithWatch"; + +describe("unittests:: tsserver:: pluginsAsync:: async loaded plugins", () => { + function setup(globalPlugins: string[]) { + const host = createServerHost([libFile]); + const session = createSession(host, { canUseEvents: true, globalPlugins, logger: createLoggerWithInMemoryLogs(host) }); + return { host, session }; + } + + it("plugins are not loaded immediately", async () => { + const { host, session } = setup(["plugin-a"]); + let pluginModuleInstantiated = false; + let pluginInvoked = false; + host.importPlugin = async (_root: string, _moduleName: string): Promise => { + await Promise.resolve(); // simulate at least a single turn delay + pluginModuleInstantiated = true; + return { + module: (() => { + pluginInvoked = true; + return { create: info => info.languageService }; + }) as ts.server.PluginModuleFactory, + error: undefined + }; + }; + + openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); + const projectService = session.getProjectService(); + + session.logger.log(`This should be false because 'executeCommand' should have already triggered plugin enablement asynchronously and there are no plugin enablements currently being processed`); + session.logger.log(`hasNewPluginEnablementRequests:: ${projectService.hasNewPluginEnablementRequests()}`); + + session.logger.log(`Should be true because async imports have already been triggered in the background`); + session.logger.log(`hasPendingPluginEnablements:: ${projectService.hasPendingPluginEnablements()}`); + + session.logger.log(`Should be false because resolution of async imports happens in a later turn`); + session.logger.log(`pluginModuleInstantiated:: ${pluginModuleInstantiated}`); + + await projectService.waitForPendingPlugins(); + + session.logger.log(`at this point all plugin modules should have been instantiated and all plugins should have been invoked`); + session.logger.log(`pluginModuleInstantiated:: ${pluginModuleInstantiated}`); + session.logger.log(`pluginInvoked:: ${pluginInvoked}`); + + baselineTsserverLogs("pluginsAsync", "plugins are not loaded immediately", session); + }); + + it("plugins evaluation in correct order even if imports resolve out of order", async () => { + const { host, session } = setup(["plugin-a", "plugin-b"]); + const pluginADeferred = defer(); + const pluginBDeferred = defer(); + host.importPlugin = async (_root: string, moduleName: string): Promise => { + session.logger.log(`request import ${moduleName}`); + const promise = moduleName === "plugin-a" ? pluginADeferred.promise : pluginBDeferred.promise; + await promise; + session.logger.log(`fulfill import ${moduleName}`); + return { + module: (() => { + session.logger.log(`invoke plugin ${moduleName}`); + return { create: info => info.languageService }; + }) as ts.server.PluginModuleFactory, + error: undefined + }; + }; + + openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); + const projectService = session.getProjectService(); + + // wait a turn + await Promise.resolve(); + + // resolve imports out of order + pluginBDeferred.resolve(); + pluginADeferred.resolve(); + + // wait for load to complete + await projectService.waitForPendingPlugins(); + + baselineTsserverLogs("pluginsAsync", "plugins evaluation in correct order even if imports resolve out of order", session); + }); + + it("sends projectsUpdatedInBackground event", async () => { + const { host, session } = setup(["plugin-a"]); + host.importPlugin = async (_root: string, _moduleName: string): Promise => { + await Promise.resolve(); // simulate at least a single turn delay + return { + module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory, + error: undefined + }; + }; + + openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); + const projectService = session.getProjectService(); + + + await projectService.waitForPendingPlugins(); + + baselineTsserverLogs("pluginsAsync", "sends projectsUpdatedInBackground event", session); + }); + + it("adds external files", async () => { + const { host, session } = setup(["plugin-a"]); + const pluginAShouldLoad = defer(); + host.importPlugin = async (_root: string, _moduleName: string): Promise => { + // wait until the initial external files are requested from the project service. + await pluginAShouldLoad.promise; + + return { + module: (() => ({ + create: info => info.languageService, + getExternalFiles: () => ["external.txt"], + })) as ts.server.PluginModuleFactory, + error: undefined + }; + }; + + openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); + const projectService = session.getProjectService(); + + const project = projectService.inferredProjects[0]; + + session.logger.log(`External files before plugin is loaded: ${project.getExternalFiles().join(",")}`); + // we've ready the initial set of external files, allow the plugin to continue loading. + pluginAShouldLoad.resolve(); + + // wait for plugins + await projectService.waitForPendingPlugins(); + + host.runQueuedTimeoutCallbacks(); + + session.logger.log(`External files before plugin after plugin is loaded: ${project.getExternalFiles().join(",")}`); + baselineTsserverLogs("pluginsAsync", "adds external files", session); + }); + + it("project is closed before plugins are loaded", async () => { + const { host, session } = setup(["plugin-a"]); + const pluginALoaded = defer(); + const projectClosed = defer(); + host.importPlugin = async (_root: string, _moduleName: string): Promise => { + // mark that the plugin has started loading + pluginALoaded.resolve(); + + // wait until after a project close has been requested to continue + await projectClosed.promise; + return { + module: (() => ({ create: info => info.languageService })) as ts.server.PluginModuleFactory, + error: undefined + }; + }; + + openFilesForSession([{ file: "^memfs:/foo.ts", content: "" }], session); + const projectService = session.getProjectService(); + + + // wait for the plugin to start loading + await pluginALoaded.promise; + + // close the project + closeFilesForSession(["^memfs:/foo.ts"], session); + + // continue loading the plugin + projectClosed.resolve(); + + await projectService.waitForPendingPlugins(); + + // the project was closed before plugins were ready. no project update should have been requested + baselineTsserverLogs("pluginsAsync", "project is closed before plugins are loaded", session); + }); +}); \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/pluginsAsync/adds-external-files.js b/tests/baselines/reference/tsserver/pluginsAsync/adds-external-files.js new file mode 100644 index 0000000000000..db15949aa5d5e --- /dev/null +++ b/tests/baselines/reference/tsserver/pluginsAsync/adds-external-files.js @@ -0,0 +1,83 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "^memfs:/foo.ts", + "fileContent": "" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: ^memfs: +Info seq [hh:mm:ss:mss] For info: ^memfs:/foo.ts :: No config files found. +Info seq [hh:mm:ss:mss] Loading global plugin plugin-a +Info seq [hh:mm:ss:mss] Enabling plugin plugin-a from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-a from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +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] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (2) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + ^memfs:/foo.ts SVC-1-0 "" + + + a/lib/lib.d.ts + Default library for target 'es5' + ^memfs:/foo.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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: ^memfs:/foo.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} + +External files before plugin is loaded: +Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Scheduled: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] got projects updated in background, updating diagnostics for ^memfs:/foo.ts +Info seq [hh:mm:ss:mss] event: + {"seq":0,"type":"event","event":"projectsUpdatedInBackground","body":{"openFiles":["^memfs:/foo.ts"]}} +Before running Timeout callback:: count: 2 +1: /dev/null/inferredProject1* +2: checkOne + +Info seq [hh:mm:ss:mss] Running: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 2 structureChanged: false structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Same program as before +Info seq [hh:mm:ss:mss] event: + {"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"^memfs:/foo.ts","diagnostics":[]}} +After running Timeout callback:: count: 0 + +External files before plugin after plugin is loaded: external.txt \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/pluginsAsync/plugins-are-not-loaded-immediately.js b/tests/baselines/reference/tsserver/pluginsAsync/plugins-are-not-loaded-immediately.js new file mode 100644 index 0000000000000..21d553ac3eb78 --- /dev/null +++ b/tests/baselines/reference/tsserver/pluginsAsync/plugins-are-not-loaded-immediately.js @@ -0,0 +1,78 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "^memfs:/foo.ts", + "fileContent": "" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: ^memfs: +Info seq [hh:mm:ss:mss] For info: ^memfs:/foo.ts :: No config files found. +Info seq [hh:mm:ss:mss] Loading global plugin plugin-a +Info seq [hh:mm:ss:mss] Enabling plugin plugin-a from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-a from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +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] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (2) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + ^memfs:/foo.ts SVC-1-0 "" + + + a/lib/lib.d.ts + Default library for target 'es5' + ^memfs:/foo.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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: ^memfs:/foo.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} + +This should be false because 'executeCommand' should have already triggered plugin enablement asynchronously and there are no plugin enablements currently being processed +hasNewPluginEnablementRequests:: false +Should be true because async imports have already been triggered in the background +hasPendingPluginEnablements:: true +Should be false because resolution of async imports happens in a later turn +pluginModuleInstantiated:: false +Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Scheduled: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] got projects updated in background, updating diagnostics for ^memfs:/foo.ts +Info seq [hh:mm:ss:mss] event: + {"seq":0,"type":"event","event":"projectsUpdatedInBackground","body":{"openFiles":["^memfs:/foo.ts"]}} +at this point all plugin modules should have been instantiated and all plugins should have been invoked +pluginModuleInstantiated:: true +pluginInvoked:: true \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/pluginsAsync/plugins-evaluation-in-correct-order-even-if-imports-resolve-out-of-order.js b/tests/baselines/reference/tsserver/pluginsAsync/plugins-evaluation-in-correct-order-even-if-imports-resolve-out-of-order.js new file mode 100644 index 0000000000000..9141b6f4f9099 --- /dev/null +++ b/tests/baselines/reference/tsserver/pluginsAsync/plugins-evaluation-in-correct-order-even-if-imports-resolve-out-of-order.js @@ -0,0 +1,79 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "^memfs:/foo.ts", + "fileContent": "" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: ^memfs: +Info seq [hh:mm:ss:mss] For info: ^memfs:/foo.ts :: No config files found. +Info seq [hh:mm:ss:mss] Loading global plugin plugin-a +Info seq [hh:mm:ss:mss] Enabling plugin plugin-a from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-a from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +request import plugin-a +Info seq [hh:mm:ss:mss] Loading global plugin plugin-b +Info seq [hh:mm:ss:mss] Enabling plugin plugin-b from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-b from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +request import plugin-b +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +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] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (2) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + ^memfs:/foo.ts SVC-1-0 "" + + + a/lib/lib.d.ts + Default library for target 'es5' + ^memfs:/foo.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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: ^memfs:/foo.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} + +fulfill import plugin-b +fulfill import plugin-a +invoke plugin plugin-a +Info seq [hh:mm:ss:mss] Plugin validation succeeded +invoke plugin plugin-b +Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Scheduled: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] got projects updated in background, updating diagnostics for ^memfs:/foo.ts +Info seq [hh:mm:ss:mss] event: + {"seq":0,"type":"event","event":"projectsUpdatedInBackground","body":{"openFiles":["^memfs:/foo.ts"]}} \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/pluginsAsync/project-is-closed-before-plugins-are-loaded.js b/tests/baselines/reference/tsserver/pluginsAsync/project-is-closed-before-plugins-are-loaded.js new file mode 100644 index 0000000000000..dfb2b144c1c49 --- /dev/null +++ b/tests/baselines/reference/tsserver/pluginsAsync/project-is-closed-before-plugins-are-loaded.js @@ -0,0 +1,89 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "^memfs:/foo.ts", + "fileContent": "" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: ^memfs: +Info seq [hh:mm:ss:mss] For info: ^memfs:/foo.ts :: No config files found. +Info seq [hh:mm:ss:mss] Loading global plugin plugin-a +Info seq [hh:mm:ss:mss] Enabling plugin plugin-a from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-a from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +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] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (2) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + ^memfs:/foo.ts SVC-1-0 "" + + + a/lib/lib.d.ts + Default library for target 'es5' + ^memfs:/foo.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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: ^memfs:/foo.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "close", + "arguments": { + "file": "^memfs:/foo.ts" + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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] response: + { + "responseRequired": false + } +After request + +Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Scheduled: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] got projects updated in background, updating diagnostics for \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/pluginsAsync/sends-projectsUpdatedInBackground-event.js b/tests/baselines/reference/tsserver/pluginsAsync/sends-projectsUpdatedInBackground-event.js new file mode 100644 index 0000000000000..8a5d0eaa737e6 --- /dev/null +++ b/tests/baselines/reference/tsserver/pluginsAsync/sends-projectsUpdatedInBackground-event.js @@ -0,0 +1,69 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/a/lib/typesMap.json" doesn't exist +Before request +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "^memfs:/foo.ts", + "fileContent": "" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: ^memfs: +Info seq [hh:mm:ss:mss] For info: ^memfs:/foo.ts :: No config files found. +Info seq [hh:mm:ss:mss] Loading global plugin plugin-a +Info seq [hh:mm:ss:mss] Enabling plugin plugin-a from candidate paths: /a/lib/tsc.js/../../.. +Info seq [hh:mm:ss:mss] Dynamically importing plugin-a from /a/lib/tsc.js/../../.. (resolved to /a/lib/tsc.js/../../../node_modules) +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +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] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (2) + /a/lib/lib.d.ts Text-1 "/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }" + ^memfs:/foo.ts SVC-1-0 "" + + + a/lib/lib.d.ts + Default library for target 'es5' + ^memfs:/foo.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +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: ^memfs:/foo.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +FsWatches:: +/a/lib/lib.d.ts: *new* + {} + +Info seq [hh:mm:ss:mss] Plugin validation succeeded +Info seq [hh:mm:ss:mss] Scheduled: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] got projects updated in background, updating diagnostics for ^memfs:/foo.ts +Info seq [hh:mm:ss:mss] event: + {"seq":0,"type":"event","event":"projectsUpdatedInBackground","body":{"openFiles":["^memfs:/foo.ts"]}} \ No newline at end of file