diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 4699e1a1d4dd6..d8322f5e7c50c 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -283,6 +283,7 @@ namespace ts.server { throttleWaitMilliseconds?: number; globalPlugins?: string[]; pluginProbeLocations?: string[]; + allowLocalPluginLoads?: boolean; } export class ProjectService { @@ -342,6 +343,7 @@ namespace ts.server { public readonly globalPlugins: ReadonlyArray; public readonly pluginProbeLocations: ReadonlyArray; + public readonly allowLocalPluginLoads: boolean; constructor(opts: ProjectServiceOptions) { this.host = opts.host; @@ -353,6 +355,7 @@ namespace ts.server { this.eventHandler = opts.eventHandler; this.globalPlugins = opts.globalPlugins || emptyArray; this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray; + this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads; Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService"); diff --git a/src/server/project.ts b/src/server/project.ts index 09c8d74c8c7f0..6aded117599c0 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -873,6 +873,12 @@ namespace ts.server { // ../../.. to walk from X/node_modules/typescript/lib/tsserver.js to X/node_modules/ const searchPaths = [combinePaths(host.getExecutingFilePath(), "../../.."), ...this.projectService.pluginProbeLocations]; + if (this.projectService.allowLocalPluginLoads) { + const local = getDirectoryPath(this.canonicalConfigFilePath); + this.projectService.logger.info(`Local plugin loading enabled; adding ${local} to search paths`); + searchPaths.unshift(local); + } + // Enable tsconfig-specified plugins if (options.plugins) { for (const pluginConfigEntry of options.plugins) { diff --git a/src/server/server.ts b/src/server/server.ts index 79cfc3882aef6..a0b994c34137f 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -16,6 +16,7 @@ namespace ts.server { telemetryEnabled: boolean; globalPlugins: string[]; pluginProbeLocations: string[]; + allowLocalPluginLoads: boolean; } const net: { @@ -403,7 +404,8 @@ namespace ts.server { logger, canUseEvents, globalPlugins: options.globalPlugins, - pluginProbeLocations: options.pluginProbeLocations}); + pluginProbeLocations: options.pluginProbeLocations, + allowLocalPluginLoads: options.allowLocalPluginLoads }); if (telemetryEnabled && typingsInstaller) { typingsInstaller.setTelemetrySender(this); @@ -744,6 +746,7 @@ namespace ts.server { const globalPlugins = (findArgument("--globalPlugins") || "").split(","); const pluginProbeLocations = (findArgument("--pluginProbeLocations") || "").split(","); + const allowLocalPluginLoads = hasArgument("--allowLocalPluginLoads"); const useSingleInferredProject = hasArgument("--useSingleInferredProject"); const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition"); @@ -761,7 +764,8 @@ namespace ts.server { telemetryEnabled, logger, globalPlugins, - pluginProbeLocations + pluginProbeLocations, + allowLocalPluginLoads }; const ioSession = new IOSession(options); diff --git a/src/server/session.ts b/src/server/session.ts index a95d46ccaaf49..cee9698d6d9a0 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -348,6 +348,7 @@ namespace ts.server { globalPlugins?: string[]; pluginProbeLocations?: string[]; + allowLocalPluginLoads?: boolean; } export class Session implements EventSender { @@ -435,7 +436,8 @@ namespace ts.server { throttleWaitMilliseconds, eventHandler: this.eventHandler, globalPlugins: opts.globalPlugins, - pluginProbeLocations: opts.pluginProbeLocations + pluginProbeLocations: opts.pluginProbeLocations, + allowLocalPluginLoads: opts.allowLocalPluginLoads }; this.projectService = new ProjectService(settings); this.gcTimer = new GcTimer(this.host, /*delay*/ 7000, this.logger);