diff --git a/crates/oxc_language_server/README.md b/crates/oxc_language_server/README.md index ca37e4ef8445b..7ab851a4cf921 100644 --- a/crates/oxc_language_server/README.md +++ b/crates/oxc_language_server/README.md @@ -22,11 +22,11 @@ This crate provides an [LSP](https://microsoft.github.io/language-server-protoco Returns the [Server Capabilities](#server-capabilities).\ Initialization Options: -| Option Key | Value(s) | Default | Description | -| ------------ | ---------------------- | ---------------- | ---------------------------------------------------------------------------------------------------- | -| `run` | `"onSave" \| "onType"` | `"onType"` | Should the server lint the files when the user is typing or saving | -| `configPath` | `` | `.oxlintrc.json` | Path to a oxlint configuration file, pass '' to enable nested configuration | -| `flags` | `Map` | `` | Special oxc language server flags, currently only one flag key is supported: `disable_nested_config` | +| Option Key | Value(s) | Default | Description | +| ------------ | ---------------------- | ---------- | ---------------------------------------------------------------------------------------------------- | +| `run` | `"onSave" \| "onType"` | `"onType"` | Should the server lint the files when the user is typing or saving | +| `configPath` | `` \| `null` | `null` | Path to a oxlint configuration file, passing a string will disable nested configuration | +| `flags` | `Map` | `` | Special oxc language server flags, currently only one flag key is supported: `disable_nested_config` | ### [initialized](https://microsoft.github.io/language-server-protocol/specification#initialized) diff --git a/crates/oxc_language_server/src/main.rs b/crates/oxc_language_server/src/main.rs index 6f2ed02b5a3ba..4462c06e4bed8 100644 --- a/crates/oxc_language_server/src/main.rs +++ b/crates/oxc_language_server/src/main.rs @@ -50,29 +50,15 @@ enum Run { #[default] OnType, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] struct Options { run: Run, - config_path: String, + config_path: Option, flags: FxHashMap, } -impl Default for Options { - fn default() -> Self { - Self { - run: Run::default(), - config_path: OXC_CONFIG_FILE.into(), - flags: FxHashMap::default(), - } - } -} - impl Options { - fn get_config_path(&self) -> Option { - if self.config_path.is_empty() { None } else { Some(PathBuf::from(&self.config_path)) } - } - fn disable_nested_configs(&self) -> bool { self.flags.contains_key("disable_nested_config") } @@ -142,11 +128,8 @@ impl LanguageServer for Backend { *self.options.lock().await = changed_options.clone(); // revalidate the config and all open files - if changed_options - .get_config_path() - .is_some_and(|path| path.to_str().unwrap() != current_option.config_path) - { - info!("config path change detected {:?}", &changed_options.get_config_path()); + if changed_options.config_path != current_option.config_path { + info!("config path change detected {:?}", &changed_options.config_path); self.init_linter_config().await; self.revalidate_open_files().await; } @@ -515,7 +498,7 @@ impl Backend { let Ok(root_path) = uri.to_file_path() else { return None; }; - let relative_config_path = self.options.lock().await.get_config_path(); + let relative_config_path = self.options.lock().await.config_path.clone(); let oxlintrc = if relative_config_path.is_some() { let config = root_path.join(relative_config_path.unwrap()); config.try_exists().expect("Invalid config file path"); diff --git a/editors/vscode/client/Config.ts b/editors/vscode/client/Config.ts index aeba997e93b37..2fdbccfdfc82d 100644 --- a/editors/vscode/client/Config.ts +++ b/editors/vscode/client/Config.ts @@ -8,7 +8,7 @@ export class Config implements ConfigInterface { private _runTrigger!: Trigger; private _enable!: boolean; private _trace!: TraceLevel; - private _configPath!: string; + private _configPath!: string | null; private _binPath: string | undefined; private _flags!: Record; @@ -24,7 +24,7 @@ export class Config implements ConfigInterface { this._runTrigger = conf.get('lint.run') || 'onType'; this._enable = conf.get('enable') ?? true; this._trace = conf.get('trace.server') || 'off'; - this._configPath = conf.get('configPath') || (useNestedConfigs ? '' : oxlintConfigFileName); + this._configPath = conf.get('configPath') || (useNestedConfigs ? null : oxlintConfigFileName); this._binPath = conf.get('path.server'); this._flags = flags; } @@ -62,7 +62,7 @@ export class Config implements ConfigInterface { .update('trace.server', value); } - get configPath(): string { + get configPath(): string | null { return this._configPath; } @@ -98,14 +98,14 @@ export class Config implements ConfigInterface { public toLanguageServerConfig(): LanguageServerConfig { return { run: this.runTrigger, - configPath: this.configPath, + configPath: this.configPath ?? null, flags: this.flags, }; } } interface LanguageServerConfig { - configPath: string; + configPath: string | null; run: Trigger; flags: Record; } @@ -141,9 +141,9 @@ interface ConfigInterface { * * `oxc.configPath` * - * @default ".oxlintrc.json" + * @default null */ - configPath: string; + configPath: string | null; /** * Path to LSP binary * `oxc.path.server` diff --git a/editors/vscode/client/config.spec.ts b/editors/vscode/client/config.spec.ts index 28d459359c33d..7a61183a21168 100644 --- a/editors/vscode/client/config.spec.ts +++ b/editors/vscode/client/config.spec.ts @@ -24,12 +24,12 @@ suite('Config', () => { strictEqual(config.runTrigger, 'onType'); strictEqual(config.enable, true); strictEqual(config.trace, 'off'); - strictEqual(config.configPath, ''); + strictEqual(config.configPath, null); strictEqual(config.binPath, ''); deepStrictEqual(config.flags, {}); }); - test('configPath defaults to empty string when using nested configs and configPath is empty', async () => { + test('configPath defaults to null when using nested configs and configPath is empty', async () => { const wsConfig = workspace.getConfiguration('oxc'); await wsConfig.update('configPath', ''); await wsConfig.update('flags', {}); @@ -37,12 +37,12 @@ suite('Config', () => { const config = new Config(); deepStrictEqual(config.flags, {}); - strictEqual(config.configPath, ''); + strictEqual(config.configPath, null); }); test('configPath defaults to .oxlintrc.json when not using nested configs and configPath is empty', async () => { const wsConfig = workspace.getConfiguration('oxc'); - await wsConfig.update('configPath', ''); + await wsConfig.update('configPath', undefined); await wsConfig.update('flags', { disable_nested_config: '' }); const config = new Config(); diff --git a/editors/vscode/client/extension.ts b/editors/vscode/client/extension.ts index ae1e5b1c20260..e0211a5d25b63 100644 --- a/editors/vscode/client/extension.ts +++ b/editors/vscode/client/extension.ts @@ -201,7 +201,9 @@ export async function activate(context: ExtensionContext) { })), synchronize: { // Notify the server about file config changes in the workspace - fileEvents: createFileEventWatchers(configService.config.configPath), + fileEvents: configService.config.configPath !== null + ? createFileEventWatchers(configService.config.configPath) + : undefined, }, initializationOptions: { settings: configService.config.toLanguageServerConfig(), @@ -251,7 +253,10 @@ export async function activate(context: ExtensionContext) { if (event.affectsConfiguration('oxc.configPath')) { client.clientOptions.synchronize = client.clientOptions.synchronize ?? {}; - client.clientOptions.synchronize.fileEvents = createFileEventWatchers(configService.config.configPath); + client.clientOptions.synchronize.fileEvents = configService.config.configPath !== null + ? createFileEventWatchers(configService.config.configPath) + : undefined; + client.restart().then(async () => { const configFiles = await findOxlintrcConfigFiles(); await sendDidChangeWatchedFilesNotificationWith(client, configFiles); diff --git a/editors/vscode/package.json b/editors/vscode/package.json index f8f28a14222f1..65817da17d1fc 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -95,9 +95,9 @@ "description": "Traces the communication between VS Code and the language server." }, "oxc.configPath": { - "type": "string", + "type": ["string", "null"], "scope": "window", - "default": "", + "default": null, "description": "Path to ESlint configuration. Keep it empty to enable nested configuration." }, "oxc.path.server": {