diff --git a/_extension/package.json b/_extension/package.json index b218b3496a..0635664c30 100644 --- a/_extension/package.json +++ b/_extension/package.json @@ -31,6 +31,11 @@ { "title": "TypeScript Native Preview", "properties": { + "typescript.native-preview.customConfigFileName": { + "type": "string", + "description": "Custom config file name to use, before defaulting to tsconfig.json/jsconfig.json.", + "tags": ["experimental"] + }, "typescript.native-preview.trace.server": { "type": "string", "enum": [ diff --git a/_extension/src/client.ts b/_extension/src/client.ts index b759501e97..f785c45ce5 100644 --- a/_extension/src/client.ts +++ b/_extension/src/client.ts @@ -94,6 +94,7 @@ export class Client { const config = vscode.workspace.getConfiguration("typescript.native-preview"); const pprofDir = config.get("pprofDir"); const pprofArgs = pprofDir ? ["--pprofDir", pprofDir] : []; + const customConfigFileName = config.get("customConfigFileName") ?? ""; const serverOptions: ServerOptions = { run: { @@ -112,7 +113,12 @@ export class Client { "typescript.native-preview", "typescript.native-preview-lsp", serverOptions, - this.clientOptions, + { + ...this.clientOptions, + initializationOptions: { + customConfigFileName, + }, + }, ); this.outputChannel.appendLine(`Starting language server...`); diff --git a/_extension/src/extension.ts b/_extension/src/extension.ts index d1fe6036eb..fd109da65f 100644 --- a/_extension/src/extension.ts +++ b/_extension/src/extension.ts @@ -19,24 +19,28 @@ export async function activate(context: vscode.ExtensionContext) { let disposeLanguageFeatures: vscode.Disposable | undefined; context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async event => { - if (event.affectsConfiguration("typescript.experimental.useTsgo")) { - if (needsExtHostRestartOnChange()) { + if (event.affectsConfiguration("typescript.experimental.useTsgo") || + event.affectsConfiguration("typescript.native-preview.configNames") || + event.affectsConfiguration("typescript.native-preview.customConfigFileName")) { + // Always require restart if configNames changed, or if environment requires restart + if (event.affectsConfiguration("typescript.native-preview.configNames") || + event.affectsConfiguration("typescript.native-preview.customConfigFileName") || + needsExtHostRestartOnChange()) { // Delay because the command to change the config setting will restart // the extension host, so no need to show a message setTimeout(async () => { - const selected = await vscode.window.showInformationMessage("TypeScript Native Preview setting has changed. Restart extensions to apply changes.", "Restart Extensions"); + const selected = await vscode.window.showInformationMessage("TypeScript Native Preview settings have changed. Restart extensions to apply changes.", "Restart Extensions"); if (selected) { vscode.commands.executeCommand("workbench.action.restartExtensionHost"); } }, 100); - } - else { + } else { + // Toggle language features dynamically when useTsgo changes and restart not required const useTsgo = vscode.workspace.getConfiguration("typescript").get("experimental.useTsgo"); if (useTsgo) { disposeLanguageFeatures = await activateLanguageFeatures(context, output, traceOutput); context.subscriptions.push(disposeLanguageFeatures); - } - else { + } else { disposeLanguageFeatures?.dispose(); disposeLanguageFeatures = undefined; } diff --git a/_submodules/TypeScript b/_submodules/TypeScript index 9e8eaa1746..add6971195 160000 --- a/_submodules/TypeScript +++ b/_submodules/TypeScript @@ -1 +1 @@ -Subproject commit 9e8eaa1746b0d09c3cd29048126ef9cf24f29c03 +Subproject commit add697119549734b24d46b30b9f6d2e757c6d53a diff --git a/internal/lsp/server.go b/internal/lsp/server.go index cecd426747..6c8837bb9c 100644 --- a/internal/lsp/server.go +++ b/internal/lsp/server.go @@ -701,15 +701,26 @@ func (s *Server) handleInitialized(ctx context.Context, params *lsproto.Initiali cwd = s.cwd } + // Read customConfigFileName from initializationOptions if provided + var customConfigFileName string + if init := s.initializeParams; init != nil && init.InitializationOptions != nil { + if m, ok := (*init.InitializationOptions).(map[string]any); ok { + if v, ok := m["customConfigFileName"].(string); ok { + customConfigFileName = v + } + } + } + s.session = project.NewSession(&project.SessionInit{ Options: &project.SessionOptions{ - CurrentDirectory: cwd, - DefaultLibraryPath: s.defaultLibraryPath, - TypingsLocation: s.typingsLocation, - PositionEncoding: s.positionEncoding, - WatchEnabled: s.watchEnabled, - LoggingEnabled: true, - DebounceDelay: 500 * time.Millisecond, + CurrentDirectory: cwd, + DefaultLibraryPath: s.defaultLibraryPath, + TypingsLocation: s.typingsLocation, + PositionEncoding: s.positionEncoding, + WatchEnabled: s.watchEnabled, + LoggingEnabled: true, + DebounceDelay: 500 * time.Millisecond, + CustomConfigFileName: customConfigFileName, }, FS: s.fs, Logger: s.logger, diff --git a/internal/project/configfileregistrybuilder.go b/internal/project/configfileregistrybuilder.go index 6dbb3c5f34..586a0b22c3 100644 --- a/internal/project/configfileregistrybuilder.go +++ b/internal/project/configfileregistrybuilder.go @@ -495,7 +495,27 @@ func (c *configFileRegistryBuilder) handleConfigChange(entry *dirty.SyncMapEntry func (c *configFileRegistryBuilder) computeConfigFileName(fileName string, skipSearchInDirectoryOfFile bool, logger *logging.LogTree) string { searchPath := tspath.GetDirectoryPath(fileName) - result, _ := tspath.ForEachAncestorDirectory(searchPath, func(directory string) (result string, stop bool) { + skipSearchInDirectoryOfFileForCustomConfig := skipSearchInDirectoryOfFile + var result string + // If custom config file is provided, search for it in directory of file and its ancestors first. + // If a custom config file is provided and not found, default to tsconfig.json/jsconfig.json. + if c.sessionOptions.CustomConfigFileName != "" { + result, _ = tspath.ForEachAncestorDirectory(searchPath, func(directory string) (result string, stop bool) { + customConfigFilePath := tspath.CombinePaths(directory, c.sessionOptions.CustomConfigFileName) + if !skipSearchInDirectoryOfFileForCustomConfig && c.FS().FileExists(customConfigFilePath) { + return customConfigFilePath, true + } + skipSearchInDirectoryOfFileForCustomConfig = false + return "", false + }) + } + + if result != "" { + logger.Logf("computeConfigFileName:: File: %s:: Result: %s", fileName, result) + return result + } + + result, _ = tspath.ForEachAncestorDirectory(searchPath, func(directory string) (result string, stop bool) { tsconfigPath := tspath.CombinePaths(directory, "tsconfig.json") if !skipSearchInDirectoryOfFile && c.FS().FileExists(tsconfigPath) { return tsconfigPath, true diff --git a/internal/project/session.go b/internal/project/session.go index 0e2b2de6b1..e6d9174698 100644 --- a/internal/project/session.go +++ b/internal/project/session.go @@ -44,6 +44,7 @@ type SessionOptions struct { WatchEnabled bool LoggingEnabled bool DebounceDelay time.Duration + CustomConfigFileName string } type SessionInit struct {